root/trunk/src/trinitycore/RASocket.cpp @ 41

Revision 41, 7.9 kB (checked in by yumileroy, 17 years ago)

[svn] * Random changes/fixes...
* Some fixes to MangChat?, more coming.
* Cleaning up scripting part and preparing to merge it into the core.

Original author: XTZGZoReX
Date: 2008-10-12 17:35:16-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19/** \file
20    \ingroup mangosd
21*/
22
23#include "Common.h"
24#include "Database/DatabaseEnv.h"
25#include "Log.h"
26#include "RASocket.h"
27#include "World.h"
28#include "Config/ConfigEnv.h"
29#include "Util.h"
30#include "AccountMgr.h"
31
32/// \todo Make this thread safe if in the future 2 admins should be able to log at the same time.
33SOCKET r;
34
35#define dropclient {Sendf("I'm busy right now, come back later."); \
36        SetCloseAndDelete(); \
37        return; \
38    }
39
40uint32 iSession=0;                                          ///< Session number (incremented each time a new connection is made)
41unsigned int iUsers=0;                                      ///< Number of active administrators
42
43typedef int(* pPrintf)(const char*,...);
44
45void ParseCommand(pPrintf zprintf, char*command);
46
47/// RASocket constructor
48RASocket::RASocket(ISocketHandler &h): TcpSocket(h)
49{
50
51    ///- Increment the session number
52    iSess =iSession++ ;
53
54    ///- Get the config parameters
55    bSecure = sConfig.GetBoolDefault( "RA.Secure", true );
56    iMinLevel = sConfig.GetIntDefault( "RA.MinLevel", 3 );
57
58    ///- Initialize buffer and data
59    iInputLength=0;
60    buff=new char[RA_BUFF_SIZE];
61    stage=NONE;
62}
63
64/// RASocket destructor
65RASocket::~RASocket()
66{
67    ///- Delete buffer and decrease active admins count
68    delete [] buff;
69
70    sLog.outRALog("Connection was closed.\n");
71
72    if(stage==OK)
73        iUsers--;
74}
75
76/// Accept an incoming connection
77void RASocket::OnAccept()
78{
79    std::string ss=GetRemoteAddress();
80    sLog.outRALog("Incoming connection from %s.\n",ss.c_str());
81    ///- If there is already an active admin, drop the connection
82    if(iUsers)
83        dropclient
84
85        ///- Else print Motd
86            Sendf("%s\r\n",sWorld.GetMotd());
87}
88
89/// Read data from the network
90void RASocket::OnRead()
91{
92    ///- Read data and check input length
93    TcpSocket::OnRead();
94
95    unsigned int sz=ibuf.GetLength();
96    if(iInputLength+sz>=RA_BUFF_SIZE)
97    {
98        sLog.outRALog("Input buffer overflow, possible DOS attack.\n");
99        SetCloseAndDelete();
100        return;
101    }
102
103    ///- If there is already an active admin (other than you), drop the connection
104    if(stage!=OK && iUsers)
105        dropclient
106
107            char *inp = new char [sz+1];
108    ibuf.Read(inp,sz);
109
110    /// \todo Can somebody explain this 'Linux bugfix'?
111    if(stage==NONE)
112        if(sz>4)                                            //linux remote telnet
113            if(memcmp(inp ,"USER ",5))
114            {
115                delete [] inp;return;
116                printf("lin bugfix");
117            }                                               //linux bugfix
118
119    ///- Discard data after line break or line feed
120    bool gotenter=false;
121    unsigned int y=0;
122    for(;y<sz;y++)
123        if(inp[y]=='\r'||inp[y]=='\n')
124    {
125        gotenter=true;
126        break;
127    }
128
129    //No buffer overflow (checked above)
130    memcpy(&buff[iInputLength],inp,y);
131    iInputLength+=y;
132    delete [] inp;
133    if(gotenter)
134    {
135
136        buff[iInputLength]=0;
137        iInputLength=0;
138        switch(stage)
139        {
140            /// <ul> <li> If the input is 'USER <username>'
141            case NONE:
142                if(!memcmp(buff,"USER ",5))                 //got "USER" cmd
143                {
144                    szLogin=&buff[5];
145
146                    ///- Get the gmlevel and password from the account table
147                    std::string login = szLogin;
148
149                    ///- Convert Account name to Upper Format
150                    AccountMgr::normilizeString(login);
151
152                    ///- Escape the Login to allow quotes in names
153                    loginDatabase.escape_string(login);
154
155                    QueryResult* result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE username = '%s'",login.c_str());
156
157                    ///- If the user is not found, deny access
158                    if(!result)
159                    {
160                        Sendf("-No such user.\r\n");
161                        sLog.outRALog("User %s does not exist.\n",szLogin.c_str());
162                        if(bSecure)SetCloseAndDelete();
163                    }
164                    else
165                    {
166                        Field *fields = result->Fetch();
167
168                        //szPass=fields[0].GetString();
169
170                        ///- if gmlevel is too low, deny access
171                        if(fields[0].GetUInt32()<iMinLevel)
172                        {
173                            Sendf("-Not enough privileges.\r\n");
174                            sLog.outRALog("User %s has no privilege.\n",szLogin.c_str());
175                            if(bSecure)SetCloseAndDelete();
176                        }   else
177                        {
178                            stage=LG;
179                        }
180                        delete result;
181                    }
182                }
183                break;
184                ///<li> If the input is 'PASS <password>' (and the user already gave his username)
185            case LG:
186                if(!memcmp(buff,"PASS ",5))                 //got "PASS" cmd
187                {                                           //login+pass ok
188                    ///- If password is correct, increment the number of active administrators
189                    std::string login = szLogin;
190                    std::string pw = &buff[5];
191
192                    AccountMgr::normilizeString(login);
193                    AccountMgr::normilizeString(pw);
194                    loginDatabase.escape_string(login);
195                    loginDatabase.escape_string(pw);
196
197                    QueryResult *check = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", login.c_str(), pw.c_str());
198                    if(check)
199                    {
200                        delete check;
201                        r=GetSocket();
202                        stage=OK;
203                        ++iUsers;
204
205                        Sendf("+Logged in.\r\n");
206                        sLog.outRALog("User %s has logged in.\n",szLogin.c_str());
207                        Sendf("TC>");
208                    }
209                    else
210                    {
211                        ///- Else deny access
212                        Sendf("-Wrong pass.\r\n");
213                        sLog.outRALog("User %s has failed to log in.\n",szLogin.c_str());
214                        if(bSecure)SetCloseAndDelete();
215                    }
216                }
217                break;
218                ///<li> If user is logged, parse and execute the command
219            case OK:
220                if(strlen(buff))
221                {
222                    sLog.outRALog("Got '%s' cmd.\n",buff);
223                    ParseCommand(&RASocket::zprintf , buff);
224                }
225                else
226                    Sendf("TC>");
227                break;
228                ///</ul>
229        };
230
231    }
232}
233
234/// Output function
235int RASocket::zprintf( const char * szText, ... )
236{
237    if( !szText ) return 0;
238    va_list ap;
239    va_start(ap, szText);
240    /// \todo Remove buffer length here. Can be >1024 (e.g. list of users)
241    char *megabuffer=new char[1024];
242    unsigned int sz=vsnprintf(megabuffer,1024,szText,ap);
243    #ifdef RA_CRYPT
244    Encrypt(megabuffer,sz);
245    #endif
246
247    send(r,megabuffer,sz,0);
248    delete [] megabuffer;
249    va_end(ap);
250    return 0;
251}
Note: See TracBrowser for help on using the browser.