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

Revision 102, 8.0 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

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