Ejemplo n.º 1
0
bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State)
{
	static const u8 HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b};

	if(!State)
	{
		PatchStateMap::iterator node = ClientStates.find(Client);
		if(node == ClientStates.end())
			return false;

		State = node->second;
	}

	ConnectionTCP *Socket = Client->getTCPConn();

	if(State->mWaitSend && Socket->getSendBufferSize()==0)
		return false;

	if(State->mState==PPatchState::PS_CONNECTED)
	{
	    Console->Print("Sending Handshake 0A");
		Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A));
		//short unsigned int packet = (short unsigned int) HANDSHAKE0A;
		//Socket->write(htons(packet));
		State->mState = PPatchState::PS_HANDSHAKE0;
		Socket->flushSendBuffer();
	}

	int PacketSize=0;
	const u8 *Packet = Socket->read(&PacketSize);
	if(PacketSize > 0)
	{
		switch(State->mState)
		{
			case PPatchState::PS_HANDSHAKE1 :
			case PPatchState::PS_HANDSHAKE0 :
                Console->Print("Handling Handshake 0 and 1");
				return HandleHandshake(Client, State, Packet, PacketSize);

			case PPatchState::PS_VERSIONREQUEST :
                Console->Print("Handling Client Versionsrequest");
				return HandleVersionRequest(Client, State, Packet, PacketSize);

			case PPatchState::PS_GETPATCHORFILE :
			case PPatchState::PS_SENDPATCH :
			case PPatchState::PS_SENDFILE :
                Console->Print("Getpatchforfile, sendpatch, sendfile");
				return HandleFileRequests(Client, State, Packet, PacketSize);
			default:
				break;
		}
	}
	return true;
}
Ejemplo n.º 2
0
bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const u8 *Packet )
{
  static const u8 GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a};
  ConnectionTCP *Socket = Client->getTCPConn();

  if ( *( u16* )&Packet[3] == 0x3787 )
  {
    Socket->write( GAMEDATA, 5 );
    State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS;
  }
  else
  {
    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( u16* )&Packet[3] );
    return ( false );
  }

  return ( true );
}
Ejemplo n.º 3
0
bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const u8 *Packet )
{
  ConnectionTCP *Socket = Client->getTCPConn();

  if ( *( u16* )&Packet[3] == 0x3787 )
  {
    static const u8 STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00};

    Socket->write( STATUS, 9 );
    State->TCP.mState = PGameState::TCP::GS_GAMEINFO;
  }
  else
  {
    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( u16* )&Packet[3] );

    return ( false );
  }

  return ( true );
}
Ejemplo n.º 4
0
bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)
{
	static u8 VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

	ConnectionTCP *Socket = Client->getTCPConn();
	if(PacketSize==9 && *(u16*)&Packet[3]==0x007b)
	{
		State->mSerial = *(u16*)&Packet[7];
		*(u16*)&VERSIONPACKET[7]=State->mSerial;
		u32 ver = Config->GetOptionInt("server_version");
		*(u32*)&VERSIONPACKET[9]=ver;
		Socket->write(VERSIONPACKET, 13);
		State->mState = PPatchState::PS_GETPATCHORFILE;
	} else
	{
		Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(u16*)&Packet[3]);
		return false;
	}

	return true;
}
Ejemplo n.º 5
0
bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)
{
	static const u8 HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73};

	ConnectionTCP *Socket = Client->getTCPConn();

	switch(State->mState)
	{
		case PPatchState::PS_HANDSHAKE0 :
		{
			if(PacketSize==6 && *(u16*)&Packet[3]==0x0280 && Packet[5]==0x64)
			{
				Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A));
				State->mState = PPatchState::PS_HANDSHAKE1;
			} else
			{
				Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(u16*)&Packet[3]);
				return false;
			}

			break;
		}

		case PPatchState::PS_HANDSHAKE1 :
		{
			if(PacketSize==6 && *(u16*)&Packet[3]==0x0080 && Packet[5]==0x6c)
				State->mState = PPatchState::PS_VERSIONREQUEST;
			else
			{
				Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(u16*)&Packet[3]);
				return false;
			}
			break;
		}
		default:
			break;
	}

	return true;
}
Ejemplo n.º 6
0
bool PGameServer::ProcessClient( PClient *Client, PGameState *State )
{
  static const u8 HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};

  if ( !State )
  {
    GameStateMap::iterator node = ClientStates.find( Client );
    if ( node == ClientStates.end() )
      return ( false );

    State = node->second;
  }

  ConnectionTCP *Socket = Client->getTCPConn();
  if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() );
  if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 )
    return ( false );

  if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED )
  {
    Socket->write( HANDSHAKE0A, 6 );
    State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0;
  }

  if ( State->TCP.mState == PGameState::TCP::GS_INGAME )
  {
    return ( HandleGame( Client, State ) );
  }
  else
  {
    int PacketSize = 0;
    const u8 *Packet = Socket->read( &PacketSize );

    if ( PacketSize > 0 )
    {
      switch ( State->TCP.mState )
      {
        case PGameState::TCP::GS_HANDSHAKE0:
          return ( HandleHandshake( State, Packet, PacketSize ) );

        case PGameState::TCP::GS_AUTHENTICATE:
          return ( HandleAuthenticate( Client, State, Packet, PacketSize ) );

        case PGameState::TCP::GS_GAMEDATA:
          return ( HandleGameData( Client, State, Packet ) );

        case PGameState::TCP::GS_REQUESTCHARS:
          return ( HandleRequestChars( Client, State, Packet ) );

        case PGameState::TCP::GS_CHARLIST:
          return ( HandleCharList( Client, State, Packet, PacketSize ) );

        case PGameState::TCP::GS_GETSTATUS:
          return ( HandleGetStatus( Client, State, Packet ) );

        case PGameState::TCP::GS_GAMEINFO:
          return ( HandleGameInfo( Client, State, Packet ) );
        default:
          break;
      }
    }
  }

  return ( true );
}
Ejemplo n.º 7
0
bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const u8 *Packet )
{
// Console->Print("Inside HandleGameInfo");//NEW added

  static u8 GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header
                            0x00, 0x00, 0x00, 0x00, // account id
                            0x00, 0x00, 0x00, 0x00, // char id
                            0x00, 0x00, 0x00, 0x00, // udp ip
                            0x00, 0x00,   // udp port
                            0x00, 0x00, 0x00, 0x00, // unknown
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00, // session key
                           };

  ConnectionTCP *Socket = Client->getTCPConn();

  if ( *( u16* )&Packet[3] == 0x3c87 )
  {
    //int PortFix = Config->GetOptionInt("debug_mode");

    ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() );
    Client->setUDPConnection( udpConn );
    if ( !udpConn )
    {
      Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() );
      ClientDisconnected( Client );
    }

    u16 Port = Client->getUDPConn()->getPort();

    if ( Port == 0 )
      Console->Print( RED, BLACK, "Client->OpenUDP() failed" );


    /* if(PortFix == 1) // removed, no more use
    {
     Port = Config->GetOptionInt("useudpport");
     Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!");
    }; */

    u32 IP;
    std::string IPServerString;
// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0)
    if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) )
    {
      IPServerString = Config->GetOption( "server_nat_ip" );
    }
    else // else client is "local" so use [server_ip]
    {
      IPServerString = Config->GetOption( "server_ip" );
    }
    IP = IPStringToDWord( IPServerString.c_str() );
//Console->Print("IP-1 %d", IP);
    if ( IP == 0 )
      IP = 0x0100007f;
//Console->Print("IP-2 %d", IP);
    *( u32* )&GameInfo[13] = IP;
    *( u16* )&GameInfo[17] = Port;
    Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port );

    *( u32* )&GameInfo[5] = Client->GetAccountID();
    *( u32* )&GameInfo[9] = Client->GetCharID();
    Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() );

    Socket->write( GameInfo, 31 );
    Socket->flushSendBuffer();

    static const u8 READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00};
    Socket->write( READY, 7 );

    State->TCP.mState = PGameState::TCP::GS_INGAME;
    State->UDP.mState = PGameState::UDP::GUS_SYNC0;
//Console->Print("Sync Reset");
    Client->ResetTransactionID();

    // Mark char as Online
    PChar *Char = Client->GetChar();
    Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect
    Client->ChangeCharLocation( Char->GetLocation(), true );

    // hello-message from server..
    /*
    std::string serverName = Config->GetOption("server_name");
    std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server.";
    char* message = (char*) helloMessage.c_str();
    Chat->send(Client, CHAT_DIRECT, "System", message, false);
    */

    bool SendBC = false;
    if ( Config->GetOptionInt( "broadcast_new" ) == 1 )
    {
      if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 )
      {
        if ( Client->GetAccountLevel() > PAL_REGPLAYER )
          SendBC = false;
        else
          SendBC = true;
      }
      else
      {
        SendBC = true;
      }
    }
    if ( SendBC == true )
    {
      std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName();
      std::string serverName = Config->GetOption( "server_name" );
      std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server.";
      char* message = ( char* ) helloMessage.c_str();

      Chat->sendOOCBroadcast( message );
    }
    //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError()));
  }
  else
  {
    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( u16* )&Packet[3] );
    return ( false );
  }

  return ( true );
}
Ejemplo n.º 8
0
bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize )
{
  static u8 Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0};
  ConnectionTCP *Socket = Client->getTCPConn();

  if ( PacketSize > 9 && *( u16* )&Packet[3] == 0x8284 )
  {
    u8 Mode = Packet[9];

    switch ( Mode )
    {
      case 6: // request list
        return ( HandleRequestChars( Client, State, Packet ) );

      case 5: // validate name
      {
        if ( PacketSize < 31 )
          return ( false );

        // check for valid name string
        bool ValidString = false;

        for ( int i = 30; i < PacketSize; i++ )
          if ( Packet[i] == 0 )
          {
            ValidString = true;
            break;
          }

        const char *Name = ( char* ) & Packet[30];
        if ( ValidString )
        {
          ValidString = PChar::IsCharnameWellFormed( Name );
        }

        if ( ValidString )
        {
          if ( Chars->CharExist( std::string( Name ) ) )
          {
            ValidString = false;
          }
        }

        if ( ValidString )
          Answer[5] = 1; // ok
        else
          Answer[5] = 2; // 2..6 => 'char name already in use!'

        // Answer[5] = 0; // => 'unknown error'
        Socket->write( Answer, 10 );
        return ( true );
      }

      case 3: // delete char
      {
        PAccount Acc( Client->GetAccountID() );
        u8 Num = Packet[PacketSize-1];

        if ( Acc.GetID() )
        {
          u32 CharID = Acc.GetCharIdBySlot( Num );

          // Also check that char is out of game
          if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) )
          {
            char query[100];
            snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID );
            if ( MySQL->GameQuery( query ) )
              Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID );
            else
            {
              Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID );

              snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID );
              if ( MySQL->GameQuery( query ) )
                Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID );

              snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID );
              if ( MySQL->GameQuery( query ) )
                Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID );

              snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID );
              if ( MySQL->GameQuery( query ) )
                Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID );

              Appartements->DeleteCharAppartements( CharID );
            }
          }
          else
            return false;
        }
        return ( true );
      }

      case 7: // create char
      {
        if ( PacketSize < 64 )
          return ( false );

        u32 Slot = * ( u32* ) & Packet[30];
        //u32 nClass =* (u32*)&Packet[34]; // Not used - indirectly redundant with Profession
        u32 Profession = * ( u32* ) & Packet[38];
        u32 Gender = * ( u32* ) & Packet[42];
        u32 Head = * ( u32* ) & Packet[46];
        u32 Torso = * ( u32* ) & Packet[50];
        u32 Legs = * ( u32* ) & Packet[54];
        u32 Faction = * ( u32* ) & Packet[58];
        u8 NameLen = Packet[62];
        u8 NZSNb = Packet[63];

        char TempName[256];
        std::strncpy( TempName, ( const char* )&Packet[64], NameLen );
        TempName[NameLen] = 0;

        Answer[5] = 2; // return error if char creation fails

        if ( PChar::IsCharnameWellFormed( TempName ) )
        {
          // check for already used char name - should not happen though
          if ( ! Chars->CharExist( std::string( TempName ) ) )
          {
            PAccount Acc( Client->GetAccountID() );
            PChar* nChar = new PChar();

            if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction,
                                       Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) )
            {
              Answer[5] = 1; // return success
            }
            delete nChar;
          }
        }

        Socket->write( Answer, 10 );
        return ( true );
      }
    }
  }
  else
  {
    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( u16* )&Packet[3] );

    return ( false );
  }

  return true;
}
Ejemplo n.º 9
0
bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const u8 *Packet )
{
  PAccount Account( Client->GetAccountID() );

  if ( !Account.GetID() )
    return false;

  ConnectionTCP *Socket = Client->getTCPConn();

  struct PCharList
  {
    u16 Unknown1;
    u16 NumSlots;
    u16 Unknown2;
  } CharList;

  PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT];

  const int CHARBASESIZE = 28;

  if ( *( u16* )&Packet[3] == 0x8284 )
  {
    CharList.NumSlots = MAX_CHARS_PER_ACCOUNT;
    int NameLengths = 0;

    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
    {
      CharEntry[i].CharID = 0;
      CharEntry[i].Type = 0;
      CharEntry[i].Color0 = 0;
      CharEntry[i].Location = 1;
      CharEntry[i].Unknown1 = 0;
      CharEntry[i].Head = 0;
      CharEntry[i].Torso = 0;
      CharEntry[i].Legs = 0;
      CharEntry[i].Unknown3 = 1;
      CharEntry[i].Unknown4 = 1;
      CharEntry[i].Unknown5 = 1;
      CharEntry[i].Unknown6 = 1;
      CharEntry[i].Unknown7 = 1;
      CharEntry[i].Unknown8 = 0;
      CharEntry[i].Unknown9 = 0;
      CharEntry[i].Unknown10 = 0;
      CharEntry[i].Unknown11 = 0;
      CharEntry[i].Unknown12 = 0;

      CharEntry[i].in_use = false;
    }

    Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT );

    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
    {
      if ( CharEntry[i].in_use )
      {
        NameLengths += CharEntry[i].NameLen;
      }
      else
      {
        CharEntry[i].CharID = 0xffffffff;
        CharEntry[i].NameLen = 0;
      }
    }

    u8 PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85};
    *( u16* )&PacketHeader[1] = sizeof( u16 ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2;
    Socket->write( PacketHeader, 5 );

    CharList.Unknown1 = 0x0000;
    CharList.Unknown2 = CHARBASESIZE;
    Socket->write( CharList.Unknown1 );
    Socket->write( CharList.NumSlots );
    Socket->write( CharList.Unknown2 );

    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
    {
      Socket->write( CharEntry[i].CharID );
      Socket->write( CharEntry[i].Type );
      Socket->write( CharEntry[i].Color0 );
      Socket->write( CharEntry[i].Unknown1 );
      Socket->write( CharEntry[i].Head );
      Socket->write( CharEntry[i].Torso );
      Socket->write( CharEntry[i].Legs );
      Socket->write( CharEntry[i].Location );
      Socket->write( CharEntry[i].NameLen );
      Socket->write( CharEntry[i].Unknown3 );
      Socket->write( CharEntry[i].Unknown4 );
      Socket->write( CharEntry[i].Unknown5 );
      Socket->write( CharEntry[i].Unknown6 );
      Socket->write( CharEntry[i].Unknown7 );
      Socket->write( CharEntry[i].Unknown8 );
      Socket->write( CharEntry[i].Unknown9 );
      Socket->write( CharEntry[i].Unknown10 );
      Socket->write( CharEntry[i].Unknown11 );
      Socket->write( CharEntry[i].Unknown12 );

      if ( CharEntry[i].Name.length() > 0 )
      {
        Socket->write( CharEntry[i].Name.c_str() );
        Socket->write(( u8 )0 );
      }
    }

    State->TCP.mState = PGameState::TCP::GS_CHARLIST;
  }
  else
  {
    Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( u16* )&Packet[3] );
    return ( false );
  }

  return ( true );
}
Ejemplo n.º 10
0
bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize )
{
  ConnectionTCP *Socket = Client->getTCPConn();

  if ( PacketSize > 20 && *( u16* )&Packet[3] == 0x8084 )
  {
    // authentication method #1
    const u8 *Key = &Packet[5];  // password key
    u16 ULen = *( u16* ) & Packet[16];  // username length
    u16 PLen = *( u16* ) & Packet[18];  // password length
    char *UserName = ( char* ) & Packet[20]; // account name
    const u8 *PW = &Packet[20+ULen]; // encoded password

    // Safety controls
    if ( 15 + ULen + PLen > PacketSize )
    {
      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );
      return false;
    }
    if ( strnlen( UserName, ULen ) == ULen )
    {
      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );
      return false;
    }

    bool Failed = false;

    PAccount Account( UserName );
    if ( Account.GetID() == 0 )
    {
      Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );
      Failed = true;
    }
    else if ( !Account.Authenticate( PW, PLen, Key ) )
    {
      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );
      Failed = true;
    }

    if ( !Failed )
    {
      Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName );
      if ( Account.GetLevel() == PAL_BANNED )
      {
        Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );
        // TODO: ban ip for an adjustable time span?
        Failed = true; // player is banned
      }

      if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )
      {
        if ( Server->GetNumClients() > Server->GetMaxClients() )
        {
          Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName );
          Failed = true; // server full
        }
      }
    }

    if ( Failed )
    {
      // TODO: is this packet correct here?
      u8 AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R',
                           'R', 'O', 'R', 0
                          };
      // TODO: send actual reason instead of ERROR
      Socket->write( AUTHFAILED, 15 );
      FinalizeClientDelayed( Client, State );
      State->TCP.mState = PGameState::TCP::GS_UNKNOWN;
      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName );
    }
    else
    {
      Client->LoggedIn( &Account );
      u8 AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                      };
      *( u32* )&AUTHOK[5] = Account.GetID();
      Socket->write( AUTHOK, 28 );
      State->TCP.mState = PGameState::TCP::GS_GAMEDATA;
      Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName );
    }
  }
  else if ( PacketSize > 29 && *( u16* )&Packet[3] == 0x0183 )
  {
    // authentication method #2, sent when game starts
    const u8 *Key = &Packet[13];  // password key
    u16 PLen = *( u16* ) & Packet[25];  // password length
    u16 ULen = *( u16* ) & Packet[27];  // username length
    char *UserName = ( char* ) & Packet[29]; // account name
    const u8 *PW = &Packet[29+ULen]; // encoded password

    // Safety controls
    if ( 24 + ULen + PLen > PacketSize )
    {
      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );
      return false;
    }
    if ( strnlen( UserName, ULen ) == ULen )
    {
      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );
      return false;
    }

    bool Failed = false;

    PAccount Account( UserName );
    if ( Account.GetID() == 0 )
    {
      Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );
      Failed = true;
    }
    else if ( !Account.Authenticate( PW, PLen, Key ) )
    {
      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );
      Failed = true;
    }

    if ( !Failed )
    {
      if ( Account.GetLevel() == PAL_BANNED )
      {
        Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );
        // TODO: ban ip for an adjustable time span?
        Failed = true; // player is banned
      }

      if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )
      {
        if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) )
        {
          Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName );
          Failed = true; // server full for non-GM users
        }
      }
      else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER )
      {
        Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName );
        Failed = true;
      }
      else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() )
      {
        Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) );
        Failed = true;
      }
      else if ( Server->GetNumClients() > Server->GetMaxClients() )
      {
        Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName );
        Failed = true; // server full even for GM users
      }
    }


    if ( !Failed )
    {
      int value = *( u32* ) & Packet[21];//i think here we must read u32 instead of u8
      u32 CharID = Account.GetCharIdBySlot( value );

      if ( Chars->LoadChar( CharID ) )
      {
        Client->SetCharID( CharID );
      }
      else
      {
        Failed = true;
      }
    }

    if ( Failed ) // something strange happened
      FinalizeClientDelayed( Client, State );
    else
    {
      Client->LoggedIn( &Account );
      /*u8 AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
      *(u32*)&AUTHOK[5]=Account->GetID();
      Socket->Write(AUTHOK, 28);*/
      //Client->SetRemoteUDPAddr(*(u32*)&Packet[5], *(u16*)&Packet[9]);
      State->TCP.mState = PGameState::TCP::GS_GETSTATUS;
      Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( u32* )&Packet[5], *( u16* )&Packet[9] );
      Client->SetRemoteUDPPort( *( int* )&Packet[9] );
    }
  }
  else
  {
    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( u16* )&Packet[3] );
    return ( false );
  }

  return ( true );
}
Ejemplo n.º 11
0
bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)
{
	static u8 STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	static u8 STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	static u8 FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00};

	ConnectionTCP *Socket = Client->getTCPConn();
	// request patch
	if(PacketSize==13 && *(u16*)&Packet[3]==0x007c)
	{
		int nmax = Config->GetOptionInt("max_file_xfers");
		if(mNumFileTransfers>=nmax)
		{
			Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());
			return false;
		}
		if(State->mPatchFile)
		{
			std::fclose(State->mPatchFile);
			State->mPatchFile=0;
			--mNumFileTransfers;
		}
		if(State->mSendFile)
		{
			Filesystem->Close(State->mSendFile);
			State->mSendFile=0;
			--mNumFileTransfers;
		}
		State->mSerial = *(u16*)&Packet[7];
		State->mCurrentPatch = *(u32*)&Packet[9];
		Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch);
		if((bool)(State->mPatchSize = StartPatch(State)))
		{
			Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize);
			*(u16*)&STARTPATCH[7]=State->mSerial;
			*(u32*)&STARTPATCH[9]=State->mPatchSize;
			Socket->write(STARTPATCH, 13);
			State->mState = PPatchState::PS_SENDPATCH;
		} else
		{
			Console->Print("Patchserver: Patch not available");
			*(u16*)&FILEERROR[7]=State->mSerial;
			Socket->write(FILEERROR, 9);
			FinalizeClientDelayed(Client, State);
			State->mState=PPatchState::PS_UNKNOWN;
			return true;
		}
	} else
	// request file
	if(PacketSize > 9 && *(u16*)&Packet[3]==0x004d)
	{
		int nmax = Config->GetOptionInt("max_file_xfers");
		if(mNumFileTransfers>=nmax)
		{
			Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());
			return false;
		}
		if(State->mPatchFile)
		{
			std::fclose(State->mPatchFile);
			State->mPatchFile=0;
			--mNumFileTransfers;
		}
		if(State->mSendFile)
		{
			Filesystem->Close(State->mSendFile);
			State->mSendFile=0;
			--mNumFileTransfers;
		}
		// request file
		State->mSerial = *(u16*)&Packet[7];
		char fn[256];
		strncpy(fn, (const char*)&Packet[10], Packet[9]);
		fn[Packet[9]]=0;
		State->mCurrentFile = fn;

		Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn);
		if((bool)(State->mFileSize = StartFile(State)))
		{
			Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize);
			*(u16*)&STARTFILE[7]=State->mSerial;
			*(u32*)&STARTFILE[9]=State->mFileSize;
			Socket->write(STARTFILE, 13);
			State->mState = PPatchState::PS_SENDFILE;
		} else
		{
			Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str());
			*(u16*)&FILEERROR[7]=State->mSerial;
			Socket->write(FILEERROR, 9);
			FinalizeClientDelayed(Client, State);
			State->mState=PPatchState::PS_UNKNOWN;
			return true;
		}
	} else
	// send patch data
	if(PacketSize==17 && *(u16*)&Packet[3]==0x007d)
	{
		State->mSerial = *(u16*)&Packet[7];
		State->mCurrentPatch = *(u32*)&Packet[9];
		State->mPatchOffset = *(u32*)&Packet[13];
		if(!SendPatchData(Client, State))
		{
			Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex());
			Console->Print("Patchserver: (probably due to garbage packets)");
			// state is undefined now, kill this client
			return false;
		}
	} else
	// send file data
	if(PacketSize > 13 && *(u16*)&Packet[3]==0x00037)
	{
		State->mSerial = *(u16*)&Packet[7];
		State->mFileOffset = *(u32*)&Packet[9];
		if(!SendFileData(Client, State))
		{
			Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex());
			Console->Print("Patchserver: (probably due to garbage packets)");
			// state is undefined now, kill this client
			return false;
		}
	} else
	{
		Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet");
		return false;
	}

	return true;
}