protected override void ProcessAuthTicket(string name, int ownKey, ulong steamId, PendingClient pendingClient, byte[] ticket)
        {
            if (pendingClient.SteamID == null)
            {
                bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
#if DEBUG
                requireSteamAuth = false;
#endif

                //steam auth cannot be done (SteamManager not initialized or no ticket given),
                //but it's not required either -> let the client join without auth
                if ((!Steam.SteamManager.IsInitialized || (ticket?.Length ?? 0) == 0) &&
                    !requireSteamAuth)
                {
                    pendingClient.Connection.Name    = name;
                    pendingClient.Name               = name;
                    pendingClient.OwnerKey           = ownKey;
                    pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
                    if (authSessionStartState != Steamworks.BeginAuthResult.OK)
                    {
                        if (requireSteamAuth)
                        {
                            RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
                            return;
                        }
                        else
                        {
                            steamId = 0;
                            pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
                        }
                    }
                    pendingClient.SteamID            = steamId;
                    pendingClient.Connection.Name    = name;
                    pendingClient.Name               = name;
                    pendingClient.OwnerKey           = ownKey;
                    pendingClient.AuthSessionStarted = true;
                }
            }
            else
            {
                if (pendingClient.SteamID != steamId)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "SteamID mismatch");
                    return;
                }
            }
        }
Beispiel #2
0
        public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
        {
            if (!isInitialized || !Steamworks.SteamServer.IsValid)
            {
                return(Steamworks.BeginAuthResult.ServerNotConnectedToSteam);
            }

            DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
            Steamworks.BeginAuthResult startResult = Steamworks.SteamServer.BeginAuthSession(authTicketData, clientSteamID);
            if (startResult != Steamworks.BeginAuthResult.OK)
            {
                DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
            }

            return(startResult);
        }
Beispiel #3
0
        private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
        {
            if (!isActive)
            {
                return;
            }

            RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamId);

            if (remotePeer == null || remotePeer.DisconnectTime != null)
            {
                return;
            }

            IWriteMessage outMsg = new WriteOnlyMessage();

            outMsg.Write(steamId);
            outMsg.Write(data, 1, dataLength - 1);

            DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];

            byte incByte      = data[1];
            bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
            bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
            bool isDisconnectMessage            = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
            bool isServerMessage    = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
            bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;

            if (!remotePeer.Authenticated)
            {
                if (!remotePeer.Authenticating)
                {
                    if (isConnectionInitializationStep)
                    {
                        remotePeer.DisconnectTime = null;

                        IReadMessage             authMsg            = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
                        ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
                        //Console.WriteLine("received init step from "+steamId.ToString()+" ("+initializationStep.ToString()+")");
                        if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
                        {
                            remotePeer.Authenticating = true;

                            authMsg.ReadString(); //skip name
                            authMsg.ReadInt32();  //skip owner key
                            authMsg.ReadUInt64(); //skip steamid
                            UInt16 ticketLength = authMsg.ReadUInt16();
                            byte[] ticket       = authMsg.ReadBytes(ticketLength);

                            Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
                            if (authSessionStartState != Steamworks.BeginAuthResult.OK)
                            {
                                DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam auth session failed to start: " + authSessionStartState.ToString());
                                return;
                            }
                        }
                    }
                }
            }

            if (remotePeer.Authenticating)
            {
                remotePeer.UnauthedMessages.Add(new RemotePeer.UnauthedMessage()
                {
                    DeliveryMethod = deliveryMethod, Message = outMsg
                });
            }
            else
            {
                byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
                Array.Resize(ref msgToSend, outMsg.LengthBytes);
                ChildServerRelay.Write(msgToSend);
            }
        }
Beispiel #4
0
        private void ReadConnectionInitializationStep(PendingClient pendingClient, NetIncomingMessage inc)
        {
            if (netServer == null)
            {
                return;
            }

            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

            ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();

            //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                int    ownKey       = inc.ReadInt32();
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                byte[] ticket       = inc.ReadBytes(ticketLength);

                if (!Client.IsValidName(name, serverSettings))
                {
                    if (OwnerConnection != null ||
                        !IPAddress.IsLoopback(pendingClient.Connection.RemoteEndPoint.Address.MapToIPv4NoThrow()) &&
                        ownerKey == null || ownKey == 0 && ownKey != ownerKey)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "The name \"" + name + "\" is invalid");
                        return;
                    }
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={version}");

                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                int contentPackageCount = inc.ReadVariableInt32();
                List <ClientContentPackage> clientContentPackages = new List <ClientContentPackage>();
                for (int i = 0; i < contentPackageCount; i++)
                {
                    string packageName = inc.ReadString();
                    string packageHash = inc.ReadString();
                    clientContentPackages.Add(new ClientContentPackage(packageName, packageHash));
                }

                //check if the client is missing any of our packages
                List <ContentPackage> missingPackages = new List <ContentPackage>();
                foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages)
                {
                    if (!serverContentPackage.HasMultiplayerIncompatibleContent)
                    {
                        continue;
                    }
                    bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash);
                    if (!packageFound)
                    {
                        missingPackages.Add(serverContentPackage);
                    }
                }

                //check if the client is using packages we don't have
                List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>();
                foreach (ClientContentPackage clientContentPackage in clientContentPackages)
                {
                    bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash);
                    if (!packageFound)
                    {
                        redundantPackages.Add(clientContentPackage);
                    }
                }

                if (missingPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                else if (missingPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }

                if (pendingClient.SteamID == null)
                {
                    bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
#if DEBUG
                    requireSteamAuth = false;
#endif

                    //steam auth cannot be done (SteamManager not initialized or no ticket given),
                    //but it's not required either -> let the client join without auth
                    if ((!Steam.SteamManager.IsInitialized || (ticket?.Length ?? 0) == 0) &&
                        !requireSteamAuth)
                    {
                        pendingClient.Name               = name;
                        pendingClient.OwnerKey           = ownKey;
                        pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
                    }
                    else
                    {
                        Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
                        if (authSessionStartState != Steamworks.BeginAuthResult.OK)
                        {
                            RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
                            return;
                        }
                        pendingClient.SteamID            = steamId;
                        pendingClient.Name               = name;
                        pendingClient.OwnerKey           = ownKey;
                        pendingClient.AuthSessionStarted = true;
                    }
                }
                else     //TODO: could remove since this seems impossible
                {
                    if (pendingClient.SteamID != steamId)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "SteamID mismatch");
                        return;
                    }
                }
                break;

            case ConnectionInitialization.Password:
                int    pwLength    = inc.ReadByte();
                byte[] incPassword = new byte[pwLength];
                inc.ReadBytes(incPassword, 0, pwLength);
                if (pendingClient.PasswordSalt == null)
                {
                    DebugConsole.ThrowError("Received password message from client without salt");
                    return;
                }
                if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
                {
                    pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    pendingClient.Retries++;
                    if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
                    {
                        string banMsg = "Failed to enter correct password too many times";
                        if (pendingClient.SteamID != null)
                        {
                            serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID.Value, banMsg, null);
                        }
                        serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.Connection.RemoteEndPoint.Address, banMsg, null);
                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
                        return;
                    }
                }
                pendingClient.UpdateTime = Timing.TotalTime;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                pendingClient.InitializationStep = ConnectionInitialization.Success;
                pendingClient.UpdateTime         = Timing.TotalTime;
                break;
            }
        }