aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/worldserver/Master.cpp49
-rw-r--r--src/server/worldserver/RemoteAccess/RARunnable.cpp91
-rw-r--r--src/server/worldserver/RemoteAccess/RARunnable.h42
-rwxr-xr-xsrc/server/worldserver/RemoteAccess/RASocket.cpp456
-rwxr-xr-xsrc/server/worldserver/RemoteAccess/RASocket.h51
-rw-r--r--src/server/worldserver/worldserver.conf.dist8
6 files changed, 432 insertions, 265 deletions
diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp
index 4dede995597..3f376de6f49 100755
--- a/src/server/worldserver/Master.cpp
+++ b/src/server/worldserver/Master.cpp
@@ -36,7 +36,7 @@
#include "CliRunnable.h"
#include "Log.h"
#include "Master.h"
-#include "RASocket.h"
+#include "RARunnable.h"
#include "TCSoap.h"
#include "Timer.h"
#include "Util.h"
@@ -114,53 +114,6 @@ public:
}
};
-class RARunnable : public ACE_Based::Runnable
-{
-public:
- RARunnable () {}
-
- void run ()
- {
- SocketHandler h;
-
- // Launch the RA listener socket
- ListenSocket<RASocket> RAListenSocket (h);
- bool usera = sConfig.GetBoolDefault ("Ra.Enable", false);
-
- if (usera)
- {
- port_t raport = sConfig.GetIntDefault ("Ra.Port", 3443);
- std::string stringip = sConfig.GetStringDefault ("Ra.IP", "0.0.0.0");
- ipaddr_t raip;
- if (!Utility::u2ip (stringip, raip))
- sLog.outError ("Trinity RA can not bind to ip %s", stringip.c_str ());
- else if (RAListenSocket.Bind (raip, raport))
- sLog.outError ("Trinity RA can not bind to port %d on %s", raport, stringip.c_str ());
- else
- {
- h.Add (&RAListenSocket);
-
- sLog.outString ("Starting Remote access listner on port %d on %s", raport, stringip.c_str ());
- }
- }
-
- // Socket Selet time is in microseconds , not miliseconds!!
- uint32 socketSelecttime = sWorld.getIntConfig(CONFIG_SOCKET_SELECTTIME);
-
- // if use ra spend time waiting for io, if not use ra ,just sleep
- if (usera)
- {
- while (!World::IsStopped())
- h.Select (0, socketSelecttime);
- }
- else
- {
- while (!World::IsStopped())
- ACE_Based::Thread::Sleep(static_cast<unsigned long> (socketSelecttime / 1000));
- }
- }
-};
-
Master::Master()
{
}
diff --git a/src/server/worldserver/RemoteAccess/RARunnable.cpp b/src/server/worldserver/RemoteAccess/RARunnable.cpp
new file mode 100644
index 00000000000..8cd8fd8aa11
--- /dev/null
+++ b/src/server/worldserver/RemoteAccess/RARunnable.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ \ingroup Trinityd
+ */
+
+#include "Common.h"
+
+#include "RARunnable.h"
+
+#include <ace/Reactor_Impl.h>
+#include <ace/TP_Reactor.h>
+#include <ace/Dev_Poll_Reactor.h>
+#include <ace/Acceptor.h>
+#include <ace/SOCK_Acceptor.h>
+
+#include "RASocket.h"
+
+RARunnable::RARunnable() : m_Reactor(NULL)
+{
+ ACE_Reactor_Impl* imp = 0;
+
+#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
+
+ imp = new ACE_Dev_Poll_Reactor();
+
+ imp->max_notify_iterations (128);
+ imp->restart (1);
+
+#else
+
+ imp = new ACE_TP_Reactor();
+ imp->max_notify_iterations (128);
+
+#endif
+
+ m_Reactor = new ACE_Reactor (imp, 1);
+}
+
+RARunnable::~RARunnable()
+{
+ delete m_Reactor;
+}
+
+void RARunnable::run()
+{
+ if (!sConfig.GetBoolDefault("Ra.Enable", false))
+ return;
+
+ ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor;
+
+ uint16 raport = sConfig.GetIntDefault("Ra.Port", 3443);
+ std::string stringip = sConfig.GetStringDefault("Ra.IP", "0.0.0.0");
+
+ ACE_INET_Addr listen_addr(raport, stringip.c_str());
+
+ if (acceptor.open(listen_addr, m_Reactor) == -1)
+ {
+ sLog.outError("Trinity RA can not bind to port %d on %s", raport, stringip.c_str());
+ return;
+ }
+
+ sLog.outString("Starting Trinity RA on port %d on %s", raport, stringip.c_str());
+
+ while (!World::IsStopped())
+ {
+ // don't be too smart to move this outside the loop
+ // the run_reactor_event_loop will modify interval
+ ACE_Time_Value interval(0, 100000);
+
+ if (m_Reactor->run_reactor_event_loop(interval) == -1)
+ break;
+ }
+
+ sLog.outStaticDebug("Trinity RA thread exiting");
+}
diff --git a/src/server/worldserver/RemoteAccess/RARunnable.h b/src/server/worldserver/RemoteAccess/RARunnable.h
new file mode 100644
index 00000000000..62ffe595ff1
--- /dev/null
+++ b/src/server/worldserver/RemoteAccess/RARunnable.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/// \addtogroup Trinityd
+/// @{
+/// \file
+
+#ifndef _TRINITY_RARUNNABLE_H_
+#define _TRINITY_RARUNNABLE_H_
+
+#include "Common.h"
+
+#include <ace/Reactor.h>
+
+class RARunnable : public ACE_Based::Runnable
+{
+public:
+ RARunnable();
+ virtual ~RARunnable();
+ void run();
+
+private:
+ ACE_Reactor* m_Reactor;
+
+};
+
+#endif /* _TRINITY_RARUNNABLE_H_ */
+/// @}
diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp
index 452b94251ac..4d3e6542692 100755
--- a/src/server/worldserver/RemoteAccess/RASocket.cpp
+++ b/src/server/worldserver/RemoteAccess/RASocket.cpp
@@ -29,202 +29,300 @@
#include "Util.h"
#include "World.h"
-#define dropclient {Sendf("I'm busy right now, come back later."); \
- SetCloseAndDelete(); \
- return; \
- }
-
-/// RASocket constructor
-RASocket::RASocket(ISocketHandler &h): TcpSocket(h), szLogin(""), iInputLength(0),
-bSecure(sConfig.GetBoolDefault("RA.Secure", true)), iMinLevel(sConfig.GetIntDefault("RA.MinLevel", 3)),
-stage(NONE)
+RASocket::RASocket()
{
- *buff = '\0';
+ iMinLevel = sConfig.GetIntDefault("RA.MinLevel", 3);
}
-/// RASocket destructor
RASocket::~RASocket()
{
- sLog.outRemote("Connection was closed.\n");
}
-/// Accept an incoming connection
-void RASocket::OnAccept()
+int RASocket::open(void *)
{
- std::string ss=GetRemoteAddress();
- sLog.outRemote("Incoming connection from %s.\n",ss.c_str());
- ///- print Motd
- Sendf("%s\r\n",sWorld.GetMotd());
+ ACE_INET_Addr remote_addr;
+
+ if (peer().get_remote_addr(remote_addr) == -1)
+ {
+ sLog.outError("RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno));
+ return -1;
+ }
+
+ sLog.outRemote("Incoming connection from %s", remote_addr.get_host_addr());
+
+ return activate();
+}
+
+int RASocket::handle_close(ACE_HANDLE, ACE_Reactor_Mask)
+{
+ sLog.outRemote("Closing connection");
+ peer().close_reader();
+ wait();
+ destroy();
+ return 0;
}
-/// Read data from the network
-void RASocket::OnRead()
+int RASocket::send(const std::string& line)
{
- ///- Read data and check input length
- TcpSocket::OnRead();
-
- unsigned int sz=ibuf.GetLength();
- if (iInputLength+sz>=RA_BUFF_SIZE)
- {
- sLog.outRemote("Input buffer overflow, possible DOS attack.\n");
- SetCloseAndDelete();
- return;
- }
-
- char *inp = new char [sz+1];
- ibuf.Read(inp,sz);
-
- /// \todo Can somebody explain this 'Linux bugfix'?
- if (stage==NONE)
- if (sz>4) //linux remote telnet
- if (memcmp(inp ,"USER ",5))
- {
- delete [] inp;return;
- printf("lin bugfix");
- } //linux bugfix
-
- ///- Discard data after line break or line feed
- bool gotenter=false;
- unsigned int y=0;
- for (; y<sz; y++)
- if (inp[y]=='\r'||inp[y]=='\n')
- {
- gotenter=true;
- break;
- }
-
- //No buffer overflow (checked above)
- memcpy(&buff[iInputLength],inp,y);
- iInputLength+=y;
- delete [] inp;
- if (gotenter)
- {
-
- buff[iInputLength]=0;
- iInputLength=0;
- switch(stage)
- {
- /// <ul> <li> If the input is 'USER <username>'
- case NONE:
- if (!memcmp(buff,"USER ",5)) //got "USER" cmd
- {
- szLogin=&buff[5];
-
- ///- Get the password from the account table
- std::string login = szLogin;
-
- ///- Convert Account name to Upper Format
- AccountMgr::normalizeString(login);
-
- ///- Escape the Login to allow quotes in names
- LoginDatabase.escape_string(login);
-
- QueryResult result = LoginDatabase.PQuery("SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = '%s'",login.c_str ());
-
- ///- If the user is not found, deny access
- if (!result)
- {
- Sendf("-No such user.\r\n");
- sLog.outRemote("User %s does not exist.\n",szLogin.c_str());
- if (bSecure)SetCloseAndDelete();
- }
- else
- {
- Field *fields = result->Fetch();
-
- //szPass=fields[0].GetString();
-
- ///- if gmlevel is too low, deny access
- if (fields[1].GetUInt32() < iMinLevel)
- {
- Sendf("-Not enough privileges.\r\n");
- sLog.outRemote("User %s has no privilege.\n",szLogin.c_str());
- if (bSecure)SetCloseAndDelete();
- }
- else if (fields[2].GetInt32() != -1)
- {
- ///- if RealmID isn't -1, deny access
- Sendf("-Not enough privileges.\r\n");
- sLog.outRemote("User %s has to be assigned on all realms (with RealmID = '-1').\n",szLogin.c_str());
- if (bSecure)SetCloseAndDelete();
- }
- else
- {
- stage=LG;
- }
- }
- }
- break;
- ///<li> If the input is 'PASS <password>' (and the user already gave his username)
- case LG:
- if (!memcmp(buff,"PASS ",5)) //got "PASS" cmd
- { //login+pass ok
- ///- If password is correct, increment the number of active administrators
- std::string login = szLogin;
- std::string pw = &buff[5];
-
- AccountMgr::normalizeString(login);
- AccountMgr::normalizeString(pw);
- LoginDatabase.escape_string(login);
- LoginDatabase.escape_string(pw);
-
- QueryResult check = LoginDatabase.PQuery(
- "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))",
- login.c_str(), login.c_str(), pw.c_str());
-
- if (check)
- {
- GetSocket();
- stage=OK;
-
- Sendf("+Logged in.\r\n");
- sLog.outRemote("User %s has logged in.\n",szLogin.c_str());
- Sendf("TC>");
- }
- else
- {
- ///- Else deny access
- Sendf("-Wrong pass.\r\n");
- sLog.outRemote("User %s has failed to log in.\n",szLogin.c_str());
- if (bSecure)SetCloseAndDelete();
- }
- }
- break;
- ///<li> If user is logged, parse and execute the command
- case OK:
- if (*buff != '\0')
- {
- sLog.outRemote("Got '%s' cmd.\n",buff);
- SetDeleteByHandler(false);
- CliCommandHolder* cmd = new CliCommandHolder(this, buff, &RASocket::zprint, &RASocket::commandFinished);
- sWorld.QueueCliCommand(cmd);
- ++pendingCommands;
- }
- else
- Sendf("TC>");
- break;
- ///</ul>
- };
-
- }
+ return peer().send(line.c_str(), line.length()) == line.length() ? 0 : -1;
+}
+
+int RASocket::recv_line(ACE_Message_Block& buffer)
+{
+ char byte;
+ for (;;)
+ {
+ ssize_t n = peer().recv(&byte, sizeof(byte));
+
+ if (n < 0)
+ {
+ return -1;
+ }
+
+ if (n == 0)
+ {
+ // EOF, connection was closed
+ errno = ECONNRESET;
+ return -1;
+ }
+
+ ACE_ASSERT(n == sizeof(byte));
+
+ if (byte == '\n')
+ break;
+ else if (byte == '\r') /* Ignore CR */
+ continue;
+ else if (buffer.copy(&byte, sizeof(byte)) == -1)
+ return -1;
+ }
+
+ const char null_term = '\0';
+ if (buffer.copy(&null_term, sizeof(null_term)) == -1)
+ return -1;
+
+ return 0;
}
-/// Output function
-void RASocket::zprint(void* callbackArg, const char * szText )
+int RASocket::recv_line(std::string& out_line)
{
- if ( !szText )
- return;
+ char buf[4096];
+
+ ACE_Data_Block db(sizeof (buf),
+ ACE_Message_Block::MB_DATA,
+ buf,
+ 0,
+ 0,
+ ACE_Message_Block::DONT_DELETE,
+ 0);
+
+ ACE_Message_Block message_block(&db,
+ ACE_Message_Block::DONT_DELETE,
+ 0);
+
+ if (recv_line(message_block) == -1)
+ {
+ sLog.outRemote("Recv error %s", ACE_OS::strerror(errno));
+ return -1;
+ }
+
+ out_line = message_block.rd_ptr();
+
+ return 0;
+}
+
+int RASocket::process_command(const std::string& command)
+{
+ if (command.length() == 0)
+ return 0;
+
+ sLog.outRemote("Got command: %s", command.c_str());
+
+ // handle quit, exit and logout commands to terminate connection
+ if (command == "quit" || command == "exit" || command == "logout") {
+ (void) send("Bye\r\n");
+ return -1;
+ }
+
+ CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished);
+ sWorld.QueueCliCommand(cmd);
+
+ // wait for result
+ ACE_Message_Block* mb;
+ for (;;)
+ {
+ if (getq(mb) == -1)
+ return -1;
+
+ if (mb->msg_type() == ACE_Message_Block::MB_BREAK)
+ {
+ mb->release();
+ break;
+ }
+
+ if (peer().send(mb->rd_ptr(), mb->length()) != mb->length())
+ {
+ mb->release();
+ return -1;
+ }
+
+ mb->release();
+ }
+
+ return 0;
+}
+
+int RASocket::check_access_level(const std::string& user)
+{
+ std::string safe_user = user;
+
+ AccountMgr::normalizeString(safe_user);
+ LoginDatabase.escape_string(safe_user);
+
+ QueryResult result = LoginDatabase.PQuery("SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = '%s'", safe_user.c_str());
+
+ if (!result)
+ {
+ sLog.outRemote("User %s does not exist in database", user.c_str());
+ return -1;
+ }
+
+ Field *fields = result->Fetch();
+
+ if (fields[1].GetUInt32() < iMinLevel)
+ {
+ sLog.outRemote("User %s has no privilege to login", user.c_str());
+ return -1;
+ }
+ else if (fields[2].GetInt32() != -1)
+ {
+ sLog.outRemote("User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str());
+ return -1;
+ }
- unsigned int sz=strlen(szText);
- send(((RASocket*)callbackArg)->GetSocket(), szText, sz, 0);
+ return 0;
+}
+
+int RASocket::check_password(const std::string& user, const std::string& pass)
+{
+ std::string safe_user = user;
+ AccountMgr::normalizeString(safe_user);
+ LoginDatabase.escape_string(safe_user);
+
+ std::string safe_pass = pass;
+ AccountMgr::normalizeString(safe_pass);
+ LoginDatabase.escape_string(safe_pass);
+
+ QueryResult check = LoginDatabase.PQuery(
+ "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))",
+ safe_user.c_str(), safe_user.c_str(), safe_pass.c_str());
+
+ if (!check)
+ {
+ sLog.outRemote("Wrong password for user: %s", user.c_str());
+ return -1;
+ }
+
+ return 0;
+}
+
+int RASocket::authenticate()
+{
+ if (send(std::string("Username: ")) == -1)
+ return -1;
+
+ std::string user;
+ if (recv_line(user) == -1)
+ return -1;
+
+ if (send(std::string("Password: ")) == -1)
+ return -1;
+
+ std::string pass;
+ if (recv_line(pass) == -1)
+ return -1;
+
+ sLog.outRemote("Login attempt for user: %s", user.c_str());
+
+ if (check_access_level(user) == -1)
+ return -1;
+
+ if (check_password(user, pass) == -1)
+ return -1;
+
+ sLog.outRemote("User login: %s", user.c_str());
+
+ return 0;
+}
+
+int RASocket::svc(void)
+{
+ if (send("Authentication required\r\n") == -1)
+ return -1;
+
+ if (authenticate() == -1)
+ {
+ (void) send("Authentication failed\r\n");
+ return -1;
+ }
+
+ // send motd
+ if (send(std::string(sWorld.GetMotd()) + "\r\n") == -1)
+ return -1;
+
+ for(;;)
+ {
+ // show prompt
+ const char* tc_prompt = "TC> ";
+ if (peer().send(tc_prompt, strlen(tc_prompt)) != strlen(tc_prompt))
+ return -1;
+
+ std::string line;
+
+ if (recv_line(line) == -1)
+ return -1;
+
+ if (process_command(line) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+void RASocket::zprint(void* callbackArg, const char * szText)
+{
+ if (!szText || !callbackArg)
+ return;
+
+ RASocket* socket = static_cast<RASocket*>(callbackArg);
+ size_t sz = strlen(szText);
+
+ ACE_Message_Block* mb = new ACE_Message_Block(sz);
+ mb->copy(szText, sz);
+
+ if (socket->putq(mb, const_cast<ACE_Time_Value*>(&ACE_Time_Value::zero)) == -1)
+ {
+ sLog.outRemote("Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno));
+ mb->release();
+ }
}
void RASocket::commandFinished(void* callbackArg, bool /*success*/)
{
- RASocket* raSocket = (RASocket*)callbackArg;
- raSocket->Sendf("TC>");
- uint64 remainingCommands = --raSocket->pendingCommands;
+ if (!callbackArg)
+ return;
- if (remainingCommands == 0)
- raSocket->SetDeleteByHandler(true);
- }
+ RASocket* socket = static_cast<RASocket*>(callbackArg);
+
+ ACE_Message_Block* mb = new ACE_Message_Block();
+
+ mb->msg_type(ACE_Message_Block::MB_BREAK);
+
+ // the message is 0 size control message to tell that command output is finished
+ // hence we don't put timeout, because it shouldn't increase queue size and shouldn't block
+ if (socket->putq(mb) == -1)
+ {
+ // getting here is bad, command can't be marked as complete
+ sLog.outRemote("Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno));
+ mb->release();
+ }
+}
diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h
index 948f6077b00..dfc82bbf56a 100755
--- a/src/server/worldserver/RemoteAccess/RASocket.h
+++ b/src/server/worldserver/RemoteAccess/RASocket.h
@@ -23,48 +23,39 @@
#ifndef _RASOCKET_H
#define _RASOCKET_H
-#include "TcpSocket.h"
-
#include "Common.h"
-#include <ace/Synch_Traits.h>
-
-#define RA_BUFF_SIZE 1024
-class ISocketHandler;
-
-typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, uint64> AtomicInt;
+#include <ace/Synch_Traits.h>
+#include <ace/Svc_Handler.h>
+#include <ace/SOCK_Stream.h>
+#include <ace/SOCK_Acceptor.h>
/// Remote Administration socket
-class RASocket: public TcpSocket
+class RASocket: public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
{
public:
+ RASocket();
+ virtual ~RASocket();
- RASocket(ISocketHandler& h);
- ~RASocket();
-
- void OnAccept();
- void OnRead();
-
- AtomicInt pendingCommands;
+ virtual int svc(void);
+ virtual int open(void * = 0);
+ virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
private:
- char buff[RA_BUFF_SIZE];
- std::string szLogin;
-
- unsigned int iInputLength;
- bool bSecure;
- //will protect from DOS, bruteforce attacks
- //some 'smart' protection must be added for more security
- uint8 iMinLevel;
- enum
- {
- NONE, //initial value
- LG, //only login was entered
- OK, //both login and pass were given, and they are correct and user have enough priv.
- }stage;
+ int recv_line(std::string& out_line);
+ int recv_line(ACE_Message_Block& buffer);
+ int process_command(const std::string& command);
+ int authenticate();
+ int check_access_level(const std::string& user);
+ int check_password(const std::string& user, const std::string& pass);
+ int send(const std::string& line);
static void zprint(void* callbackArg, const char * szText );
static void commandFinished(void* callbackArg, bool success);
+
+ private:
+ /// Minimum security level required to connect
+ uint8 iMinLevel;
};
#endif
/// @}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 0e3654a9744..6469b07c793 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2519,14 +2519,6 @@ Ra.Port = 3443
Ra.MinLevel = 3
#
-# Ra.Secure
-# Description: Kick clients on invalid authentication.
-# Default: 1 - (Enabled)
-# 0 - (Disabled)
-
-Ra.Secure = 1
-
-#
# SOAP.Enable
# Description: Enable soap service
# Default: 0 - (Disabled)