Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/murmur.ini39
-rw-r--r--src/ACL.cpp21
-rw-r--r--src/ACL.h4
-rw-r--r--src/Connection.cpp4
-rw-r--r--src/Timer.cpp2
-rw-r--r--src/Timer.h2
-rw-r--r--src/murmur/Cert.cpp16
-rw-r--r--src/murmur/DBus.cpp16
-rw-r--r--src/murmur/DBus_fake.h2
-rw-r--r--src/murmur/Messages.cpp44
-rw-r--r--src/murmur/Meta.cpp46
-rw-r--r--src/murmur/Meta.h9
-rw-r--r--src/murmur/Register.cpp8
-rw-r--r--src/murmur/Server.cpp125
-rw-r--r--src/murmur/Server.h54
-rw-r--r--src/murmur/ServerDB.cpp20
-rw-r--r--src/murmur/murmur.cpp10
17 files changed, 247 insertions, 175 deletions
diff --git a/scripts/murmur.ini b/scripts/murmur.ini
index 0d5f1ac6e..147ed7857 100644
--- a/scripts/murmur.ini
+++ b/scripts/murmur.ini
@@ -1,13 +1,3 @@
-# Welcome message sent to users
-welcometext="<br />Welcome to this server running <b>Murmur</b>.<br />Enjoy your stay!<br />"
-
-# Port to bind TCP and UDP sockets to
-port=64738
-
-# Specific IP or hostname to bind to.
-# If this is left blank (default), murmur will bind to all available addresses.
-#host=
-
# Path to database. If blank, will search for
# murmur.sqlite in default locations.
database=
@@ -27,10 +17,33 @@ database=
#
#dbus=session
+# How many login attempts do we tolerate from one IP
+# inside a given timeframe before we ban the connection?
+# Note that this is global (shared between all virtual servers), and that
+# it counts both successfull and unsuccessfull connection attempts.
+# Set either Attempts or Timeframe to 0 to disable.
+#autobanAttempts = 10
+#autobanTimeframe = 120
+#autobanTime = 300
+
# Murmur default to logging to murmur.log. If you leave this blank,
# murmur will log to the console (linux) or through message boxes (win32).
#logfile=murmur.log
+# The below will be used as defaults for new configured servers.
+# If you're just running one server (the default), it's easier to
+# configure it here than through DBus/SQL.
+#
+# Welcome message sent to users
+welcometext="<br />Welcome to this server running <b>Murmur</b>.<br />Enjoy your stay!<br />"
+
+# Port to bind TCP and UDP sockets to
+port=64738
+
+# Specific IP or hostname to bind to.
+# If this is left blank (default), murmur will bind to all available addresses.
+#host=
+
# Password to join server
serverpassword=
@@ -56,9 +69,3 @@ users=50
# If you have a proper SSL certificate, you can provide the filenames here.
#sslCert=
#sslKey=
-
-# If no key can be loaded, murmur will generate one for you, and store it
-# in this file for later use. If no filename is specified, 'murmur.pem'
-# will be used by default.
-# sslStore=
-
diff --git a/src/ACL.cpp b/src/ACL.cpp
index 58244f7e3..0ad73f6da 100644
--- a/src/ACL.cpp
+++ b/src/ACL.cpp
@@ -56,14 +56,21 @@ bool ChanACL::hasPermission(Player *p, Channel *chan, Perm perm, ACLCache &cache
ChanACL *acl;
// Superuser
- if (p->iId == 0)
- return true;
+ if (p->iId == 0) {
+ switch (perm) {
+ case Speak:
+ case AltSpeak:
+ return false;
+ default:
+ return true;
+ }
+ }
Permissions granted = 0;
- QHash<Player *, Permissions> *h = cache.value(chan);
+ QHash<Channel *, Permissions> *h = cache.value(p);
if (h)
- granted = h->value(p);
+ granted = h->value(chan);
if (granted & Cached) {
if ((perm != Speak) && (perm != AltSpeak))
return ((granted & (perm | Write)) != None);
@@ -114,10 +121,10 @@ bool ChanACL::hasPermission(Player *p, Channel *chan, Perm perm, ACLCache &cache
}
}
- if (! cache.contains(chan))
- cache.insert(chan, new QHash<Player *, Permissions>);
+ if (! cache.contains(p))
+ cache.insert(p, new QHash<Channel *, Permissions>);
- cache.value(chan)->insert(p, granted | Cached);
+ cache.value(p)->insert(chan, granted | Cached);
if ((perm != Speak) && (perm != AltSpeak))
return ((granted & (perm | Write)) != None);
diff --git a/src/ACL.h b/src/ACL.h
index b0b56844f..ac6708dbb 100644
--- a/src/ACL.h
+++ b/src/ACL.h
@@ -56,8 +56,8 @@ class ChanACL : public QObject {
Q_DECLARE_FLAGS(Permissions, Perm)
- typedef QHash<Player *, Permissions> ChanCache;
- typedef QHash<Channel *, ChanCache * > ACLCache;
+ typedef QHash<Channel *, Permissions> ChanCache;
+ typedef QHash<Player *, ChanCache * > ACLCache;
// static QHash<Channel *, QHash<Player *, Permissions > > c_qhACLCache;
diff --git a/src/Connection.cpp b/src/Connection.cpp
index 9d39a751d..533f143c1 100644
--- a/src/Connection.cpp
+++ b/src/Connection.cpp
@@ -106,14 +106,10 @@ void Connection::socketError(QAbstractSocket::SocketError) {
}
void Connection::socketSslErrors(const QList<QSslError> &qlErr) {
- foreach(QSslError e, qlErr) {
- qDebug("Ssl Error: %s",qPrintable(e.errorString()));
- }
emit handleSslErrors(qlErr);
}
void Connection::proceedAnyway() {
- qDebug("Allowing SSL connection to proceed.");
qtsSocket->ignoreSslErrors();
}
diff --git a/src/Timer.cpp b/src/Timer.cpp
index 6de456490..ca25dd6a1 100644
--- a/src/Timer.cpp
+++ b/src/Timer.cpp
@@ -35,7 +35,7 @@ Timer::Timer() {
uiStart = now();
}
-quint64 Timer::elapsed() {
+quint64 Timer::elapsed() const {
return now() - uiStart;
}
diff --git a/src/Timer.h b/src/Timer.h
index f8f90cca9..fa6d5c582 100644
--- a/src/Timer.h
+++ b/src/Timer.h
@@ -39,7 +39,7 @@ protected:
static quint64 now();
public:
Timer();
- quint64 elapsed();
+ quint64 elapsed() const;
quint64 restart();
};
diff --git a/src/murmur/Cert.cpp b/src/murmur/Cert.cpp
index c2083c7e6..8a734835d 100644
--- a/src/murmur/Cert.cpp
+++ b/src/murmur/Cert.cpp
@@ -61,14 +61,14 @@ void Server::initializeCert() {
if (! crt.isEmpty()) {
qscCert = QSslCertificate(crt);
if (qscCert.isNull()) {
- qWarning("Failed to parse certificate.");
+ log("Failed to parse certificate.");
}
}
if (! key.isEmpty() && qscCert.isNull()) {
qscCert = QSslCertificate(key);
if (! qscCert.isNull()) {
- qDebug("Using certificate from key file.");
+ log("Using certificate from key.");
}
}
@@ -78,14 +78,14 @@ void Server::initializeCert() {
if (! key.isEmpty()) {
qskKey = QSslKey(key, alg);
if (qskKey.isNull()) {
- qWarning("Failed to parse key file.");
+ log("Failed to parse key.");
}
}
if (! crt.isEmpty() && qskKey.isNull()) {
qskKey = QSslKey(crt, alg);
if (! qskKey.isNull()) {
- qDebug("Using key from certificate file.");
+ log("Using key from certificate.");
}
}
@@ -93,12 +93,12 @@ void Server::initializeCert() {
if (qscCert.isNull() || qskKey.isNull()) {
if (! key.isEmpty() || ! crt.isEmpty()) {
- qFatal("Certificate specified, but failed to load.");
+ log("Certificate specified, but failed to load.");
}
qskKey = Meta::mp.qskKey;
qscCert = Meta::mp.qscCert;
if (qscCert.isNull() || qskKey.isNull()) {
- qWarning("Generating new server certificate.");
+ log("Generating new server certificate.");
BIO *bio_err;
@@ -135,7 +135,7 @@ void Server::initializeCert() {
qscCert = QSslCertificate(crt, QSsl::Der);
if (qscCert.isNull())
- qFatal("Certificate generation failed");
+ log("Certificate generation failed");
key.resize(i2d_PrivateKey(pkey, NULL));
dptr=reinterpret_cast<unsigned char *>(key.data());
@@ -143,7 +143,7 @@ void Server::initializeCert() {
qskKey = QSslKey(key, QSsl::Rsa, QSsl::Der);
if (qskKey.isNull())
- qFatal("Key generation failed");
+ log("Key generation failed");
setConf("certificate", qscCert.toPem());
setConf("key", qskKey.toPem());
diff --git a/src/murmur/DBus.cpp b/src/murmur/DBus.cpp
index 2b1dcfc1b..484bfd650 100644
--- a/src/murmur/DBus.cpp
+++ b/src/murmur/DBus.cpp
@@ -153,7 +153,7 @@ QString MurmurDBus::mapIdToName(int id) {
if (reply.isValid())
return reply.value();
else {
- qWarning("Authenticator failed getUserName for %d: %s", id, qPrintable(reply.error().message()));
+ server->log("DBus Authenticator failed getUserName for %d: %s", id, qPrintable(reply.error().message()));
qsAuthPath = QString();
qsAuthService = QString();
return QString();
@@ -183,7 +183,7 @@ int MurmurDBus::mapNameToId(const QString &name) {
if (reply.isValid())
return reply.value();
else {
- qWarning("Authenticator failed getUserId for %s: %s", qPrintable(name), qPrintable(reply.error().message()));
+ server->log("DBus Authenticator failed getUserId for %s: %s", qPrintable(name), qPrintable(reply.error().message()));
qsAuthPath = QString();
qsAuthService = QString();
return -2;
@@ -211,14 +211,14 @@ int MurmurDBus::authenticate(QString &uname, const QString &pw) {
}
}
if (ok) {
- qWarning("Authenticate success for %s: %d", qPrintable(uname),uid);
+ server->log("DBus Authenticate success for %s: %d", qPrintable(uname),uid);
return uid;
} else {
- qWarning("Autenticator failed authenticate for %s: Invalid return type", qPrintable(uname));
+ server->log("DBus Autenticator failed authenticate for %s: Invalid return type", qPrintable(uname));
return -2;
}
} else {
- qWarning("Authenticator failed authenticate for %s: %s", qPrintable(uname), qPrintable(err.message()));
+ server->log("DBus Authenticator failed authenticate for %s: %s", qPrintable(uname), qPrintable(err.message()));
qsAuthPath = QString();
qsAuthService = QString();
return -2;
@@ -569,7 +569,7 @@ void MurmurDBus::getPlayerIds(const QStringList &names, const QDBusMessage &, QL
void MurmurDBus::setAuthenticator(const QDBusObjectPath &path, const QDBusMessage &msg) {
qsAuthPath = path.path();
qsAuthService = msg.service();
- qWarning("Authenticator set to %s %s",qPrintable(qsAuthService),qPrintable(qsAuthPath));
+ server->log("DBus Authenticator set to %s %s",qPrintable(qsAuthService),qPrintable(qsAuthPath));
}
void MurmurDBus::setTemporaryGroups(int channel, int playerid, const QStringList &groups, const QDBusMessage &msg) {
@@ -588,7 +588,9 @@ void MurmurDBus::setTemporaryGroups(int channel, int playerid, const QStringList
g->qsTemporary.insert(playerid);
}
- server->clearACLCache();
+ Player *p = server->qhUsers.value(playerid);
+ if (p)
+ server->clearACLCache(p);
}
PlayerInfo::PlayerInfo(Player *p) {
diff --git a/src/murmur/DBus_fake.h b/src/murmur/DBus_fake.h
index c24ba0eb1..713e30d87 100644
--- a/src/murmur/DBus_fake.h
+++ b/src/murmur/DBus_fake.h
@@ -65,8 +65,6 @@ class MurmurDBus : public QObject {
};
};
-extern MurmurDBus *dbus;
-
#else
class MurmurDBus;
#endif
diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp
index e984d27a9..215a9a1d1 100644
--- a/src/murmur/Messages.cpp
+++ b/src/murmur/Messages.cpp
@@ -53,7 +53,7 @@
#define PERM_DENIED(who, where, what) \
mpd.qsReason = QString("%1 not allowed to %2 in %3").arg(who->qsName).arg(ChanACL::permName(what)).arg(where->qsName); \
sendMessage(cCon, &mpd); \
- log(mpd.qsReason, cCon)
+ log(uSource, "%s", qPrintable(mpd.qsReason))
#define PERM_DENIED_TEXT(text) \
mpd.qsReason = text; \
sendMessage(cCon, &mpd)
@@ -139,7 +139,7 @@ void Server::msgServerAuthenticate(Connection *cCon, MessageServerAuthenticate *
}
if (! ok) {
- log(QString::fromLatin1("Rejected connection: %1").arg(msr.qsReason), cCon);
+ log(uSource, "Rejected connection: %s", qPrintable(msr.qsReason));
sendMessage(cCon, &msr);
cCon->disconnectSocket();
return;
@@ -147,7 +147,7 @@ void Server::msgServerAuthenticate(Connection *cCon, MessageServerAuthenticate *
// Kick ghost
if (uOld) {
- log(QString::fromLatin1("Disconnecting ghost"), uOld);
+ log(uSource, "Disconnecting ghost");
uOld->disconnectSocket();
}
@@ -246,7 +246,7 @@ void Server::msgServerAuthenticate(Connection *cCon, MessageServerAuthenticate *
mssMsg.qsWelcomeText = qsWelcomeText;
mssMsg.iMaxBandwidth = iMaxBandwidth;
sendMessage(cCon, &mssMsg);
- log(QString("Authenticated: %1").arg(msg->qsUsername), cCon);
+ log(uSource, "Authenticated");
dbus->playerConnected(uSource);
playerEnterChannel(uSource, lc, false);
@@ -268,7 +268,7 @@ void Server::msgServerBanList(Connection *cCon, MessageServerBanList *msg) {
} else {
qlBans = msg->qlBans;
saveBans();
- log(QString("Updated banlist"), cCon);
+ log(uSource, "Updated banlist");
}
}
@@ -308,7 +308,7 @@ void Server::msgPlayerMute(Connection *cCon, MessagePlayerMute *msg) {
if (! pDstUser)
return;
- if (! hasPermission(uSource, pDstUser->cChannel, ChanACL::MuteDeafen)) {
+ if ((pDstUser->iId ==0) || ! hasPermission(uSource, pDstUser->cChannel, ChanACL::MuteDeafen)) {
PERM_DENIED(uSource, pDstUser->cChannel, ChanACL::MuteDeafen);
return;
}
@@ -328,7 +328,7 @@ void Server::msgPlayerMute(Connection *cCon, MessagePlayerMute *msg) {
dbus->playerStateChanged(pDstUser);
- log(QString("Muted %1 (%2)").arg(pDstUser->qsName).arg(msg->bMute), cCon);
+ log(uSource, "Muted %s (%d)", qPrintable(pDstUser->qsName), msg->bMute);
}
void Server::msgPlayerDeaf(Connection *cCon, MessagePlayerDeaf *msg) {
@@ -338,7 +338,7 @@ void Server::msgPlayerDeaf(Connection *cCon, MessagePlayerDeaf *msg) {
if (! pDstUser)
return;
- if (! hasPermission(uSource, pDstUser->cChannel, ChanACL::MuteDeafen)) {
+ if ((pDstUser->iId ==0) || ! hasPermission(uSource, pDstUser->cChannel, ChanACL::MuteDeafen)) {
PERM_DENIED(uSource, pDstUser->cChannel, ChanACL::MuteDeafen);
return;
}
@@ -355,7 +355,7 @@ void Server::msgPlayerDeaf(Connection *cCon, MessagePlayerDeaf *msg) {
dbus->playerStateChanged(pDstUser);
- log(QString("Deafened %1 (%2)").arg(pDstUser->qsName).arg(msg->bDeaf), cCon);
+ log(uSource, "Deafened %s (%d)", qPrintable(pDstUser->qsName),msg->bDeaf);
}
void Server::msgPlayerKick(Connection *cCon, MessagePlayerKick *msg) {
@@ -365,13 +365,13 @@ void Server::msgPlayerKick(Connection *cCon, MessagePlayerKick *msg) {
if (! pDstUser)
return;
- if (! hasPermission(uSource, pDstUser->cChannel, ChanACL::MoveKick)) {
+ if ((pDstUser->iId ==0) || ! hasPermission(uSource, pDstUser->cChannel, ChanACL::MoveKick)) {
PERM_DENIED(uSource, pDstUser->cChannel, ChanACL::MoveKick);
return;
}
sendAll(msg);
- log(QString("Kicked %1 (%2)").arg(pDstUser->qsName).arg(msg->qsReason), cCon);
+ log(uSource, "Kicked %s (%s)", qPrintable(pDstUser->qsName), qPrintable(msg->qsReason));
pDstUser->disconnectSocket();
}
@@ -382,13 +382,13 @@ void Server::msgPlayerBan(Connection *cCon, MessagePlayerBan *msg) {
if (! pDstUser)
return;
- if (! hasPermission(uSource, qhChannels.value(0), ChanACL::MoveKick)) {
+ if ((pDstUser->iId ==0) || ! hasPermission(uSource, qhChannels.value(0), ChanACL::MoveKick)) {
PERM_DENIED(uSource, qhChannels.value(0), ChanACL::MoveKick);
return;
}
sendAll(msg);
- log(QString("Kickbanned %1 (%2)").arg(pDstUser->qsName).arg(msg->qsReason), cCon);
+ log(uSource, "Kickbanned %s (%s)", qPrintable(pDstUser->qsName), qPrintable(msg->qsReason));
QHostAddress adr = pDstUser->peerAddress();
quint32 base = adr.toIPv4Address();
@@ -418,7 +418,7 @@ void Server::msgPlayerMove(Connection *cCon, MessagePlayerMove *msg) {
if (!c || (c == pDstUser->cChannel))
return;
- if ((uSource != pDstUser) && ! hasPermission(uSource, pDstUser->cChannel, ChanACL::MoveKick)) {
+ if ((uSource != pDstUser) && ((pDstUser->iId ==0) || ! hasPermission(uSource, pDstUser->cChannel, ChanACL::MoveKick))) {
PERM_DENIED(uSource, pDstUser->cChannel, ChanACL::MoveKick);
return;
}
@@ -430,7 +430,7 @@ void Server::msgPlayerMove(Connection *cCon, MessagePlayerMove *msg) {
sendAll(msg);
playerEnterChannel(pDstUser, c);
- log(QString("Moved to %1 (%2)").arg(c->qsName).arg(pDstUser->qsName), cCon);
+ log(uSource, "Moved %s to %s",qPrintable(pDstUser->qsName), qPrintable(c->qsName));
}
void Server::msgChannelAdd(Connection *cCon, MessageChannelAdd *msg) {
@@ -469,7 +469,7 @@ void Server::msgChannelAdd(Connection *cCon, MessageChannelAdd *msg) {
msg->iId = c->iId;
sendAll(msg);
- log(QString("Added channel %1 (%2)").arg(c->qsName).arg(p->qsName), cCon);
+ log(uSource, "Added channel %s (%s)", qPrintable(c->qsName), qPrintable(p->qsName));
}
void Server::msgChannelRemove(Connection *cCon, MessageChannelRemove *msg) {
@@ -484,7 +484,7 @@ void Server::msgChannelRemove(Connection *cCon, MessageChannelRemove *msg) {
return;
}
- log(QString("Removed channel %1").arg(c->qsName), cCon);
+ log(uSource, "Removed channel %s",qPrintable(c->qsName));
removeChannel(c, uSource);
}
@@ -518,7 +518,7 @@ void Server::msgChannelMove(Connection *cCon, MessageChannelMove *msg) {
p = p->cParent;
}
- log(QString("Moved channel %1 (%2 -> %3)").arg(c->qsName).arg(c->cParent->qsName).arg(np->qsName), cCon);
+ log(uSource, "Moved channel %s from %s to %s", qPrintable(c->qsName), qPrintable(c->cParent->qsName), qPrintable(np->qsName));
c->cParent->removeChannel(c);
np->addChannel(c);
@@ -570,20 +570,20 @@ void Server::msgChannelLink(Connection *cCon, MessageChannelLink *msg) {
c->unlink(NULL);
removeLink(c, NULL);
dbus->channelStateChanged(c);
- log(QString("Unlinked all from channel %1").arg(c->qsName), cCon);
+ log(uSource, "Unlinked all from channel %s", qPrintable(c->qsName));
sendAll(msg);
return;
case MessageChannelLink::Link:
c->link(l);
addLink(c, l);
dbus->channelStateChanged(c);
- log(QString("Linked channel %1 and %2").arg(c->qsName).arg(l->qsName), cCon);
+ log(uSource, "Linked channel %s to %s", qPrintable(c->qsName),qPrintable(l->qsName));
break;
case MessageChannelLink::Unlink:
c->unlink(l);
removeLink(c, l);
dbus->channelStateChanged(c);
- log(QString("Unlinked channel %1 and %2").arg(c->qsName).arg(l->qsName), cCon);
+ log(uSource, "Unlinked channel %s from %s", qPrintable(c->qsName), qPrintable(l->qsName));
break;
case MessageChannelLink::PushLink:
foreach(int tid, msg->qlTargets) {
@@ -752,7 +752,7 @@ void Server::msgEditACL(Connection *cCon, MessageEditACL *msg) {
}
updateChannel(c);
- log(QString("Updated ACL in channel %1(%2)").arg(c->qsName).arg(c->iId), cCon);
+ log(uSource, "Updated ACL in channel %s[%d]", qPrintable(c->qsName), c->iId);
}
}
diff --git a/src/murmur/Meta.cpp b/src/murmur/Meta.cpp
index 26dc400ff..ed24573dc 100644
--- a/src/murmur/Meta.cpp
+++ b/src/murmur/Meta.cpp
@@ -47,6 +47,10 @@ MetaParams::MetaParams() {
qsDBDriver = "QSQLITE";
qsLogfile = "murmur.log";
qhaBind = QHostAddress(QHostAddress::Any);
+
+ iBanTries = 10;
+ iBanTimeframe = 120;
+ iBanTime = 300;
}
void MetaParams::read(QString fname) {
@@ -58,7 +62,7 @@ void MetaParams::read(QString fname) {
}
QSettings qs(fname, QSettings::IniFormat);
- qDebug("Initializing settings from %s", qPrintable(qs.fileName()));
+ qWarning("Initializing settings from %s", qPrintable(qs.fileName()));
QString qsHost = qs.value("host", QString()).toString();
if (! qsHost.isEmpty()) {
@@ -75,7 +79,7 @@ void MetaParams::read(QString fname) {
}
}
- qDebug("Binding to address %s", qPrintable(qhaBind.toString()));
+ qWarning("Binding to address %s", qPrintable(qhaBind.toString()));
}
qsPassword = qs.value("serverpassword", qsPassword).toString();
@@ -102,6 +106,10 @@ void MetaParams::read(QString fname) {
qsRegHost = qs.value("registerHostname", qsRegHost).toString();
qurlRegWeb = QUrl(qs.value("registerUrl", qurlRegWeb.toString()).toString());
+ iBanTries = qs.value("autobanAttempts", iBanTries).toInt();
+ iBanTimeframe = qs.value("autobanTimeframe", iBanTimeframe).toInt();
+ iBanTime = qs.value("autobanTime", iBanTime).toInt();
+
QString qsSSLCert = qs.value("sslCert").toString();
QString qsSSLKey = qs.value("sslKey").toString();
@@ -136,7 +144,7 @@ void MetaParams::read(QString fname) {
if (! key.isEmpty() && qscCert.isNull()) {
qscCert = QSslCertificate(key);
if (! qscCert.isNull()) {
- qDebug("Using certificate from key file.");
+ qWarning("Using certificate from key file.");
}
}
@@ -153,12 +161,18 @@ void MetaParams::read(QString fname) {
if (! crt.isEmpty() && qskKey.isNull()) {
qskKey = QSslKey(crt, alg);
if (! qskKey.isNull()) {
- qDebug("Using key from certificate file.");
+ qWarning("Using key from certificate file.");
}
}
if (qskKey.isNull())
qscCert = QSslCertificate();
}
+
+ if (qscCert.isNull() || qskKey.isNull()) {
+ if (! key.isEmpty() || ! crt.isEmpty()) {
+ qFatal("Certificate specified, but failed to load.");
+ }
+ }
}
Meta::Meta() {
@@ -187,3 +201,27 @@ void Meta::kill(int srvnum) {
return;
delete s;
}
+
+bool Meta::banCheck(const QHostAddress &addr) {
+ if ((mp.iBanTries == 0) || (mp.iBanTimeframe == 0))
+ return false;
+
+ if (qhBans.contains(addr)) {
+ Timer t = qhBans.value(addr);
+ if (t.elapsed() < (1000000ULL * mp.iBanTime))
+ return true;
+ qhBans.remove(addr);
+ }
+
+ QList<Timer> &ql = qhAttempts[addr];
+
+ ql.append(Timer());
+ while (! ql.isEmpty() && (ql.at(0).elapsed() > (1000000ULL * mp.iBanTimeframe)))
+ ql.removeFirst();
+
+ if (ql.count() > mp.iBanTries) {
+ qhBans.insert(addr, Timer());
+ return true;
+ }
+ return false;
+}
diff --git a/src/murmur/Meta.h b/src/murmur/Meta.h
index 00bc30abc..b07ed134f 100644
--- a/src/murmur/Meta.h
+++ b/src/murmur/Meta.h
@@ -44,6 +44,10 @@ struct MetaParams {
QString qsPassword;
QString qsWelcomeText;
+ int iBanTries;
+ int iBanTimeframe;
+ int iBanTime;
+
QString qsDatabase;
QString qsDBDriver;
QString qsDBUserName;
@@ -72,13 +76,18 @@ class Meta : public QObject {
public:
static MetaParams mp;
QHash<int, Server *> qhServers;
+ QHash<QHostAddress, QList<Timer> > qhAttempts;
+ QHash<QHostAddress, Timer> qhBans;
Meta();
void bootAll();
bool boot(int);
+ bool banCheck(const QHostAddress &);
void kill(int);
};
+extern Meta meta;
+
#else
class Meta;
#endif
diff --git a/src/murmur/Register.cpp b/src/murmur/Register.cpp
index eed480b6e..d8747eed2 100644
--- a/src/murmur/Register.cpp
+++ b/src/murmur/Register.cpp
@@ -40,9 +40,9 @@ void Server::initRegister() {
if ((! qsRegName.isEmpty()) && (! qsRegPassword.isEmpty()) && (qurlRegWeb.isValid()) && (qsPassword.isEmpty()))
qtTick.start(60000);
else
- qWarning("Registration needs nonempty name, password and url, and the server must not be password protected.");
+ log("Registration needs nonempty name, password and url, and the server must not be password protected.");
} else {
- qWarning("Not registering server as public");
+ log("Not registering server as public");
}
}
@@ -113,10 +113,10 @@ void Server::update() {
void Server::done(bool err) {
if (err) {
- qWarning("Regstration failed: %s", qPrintable(http->errorString()));
+ log("Regstration failed: %s", qPrintable(http->errorString()));
} else {
QByteArray qba = http->readAll();
- qWarning("Registration: %s", qPrintable(QString(QLatin1String(qba))));
+ log("Registration: %s", qPrintable(QString(QLatin1String(qba))));
}
abort();
}
diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp
index b75011682..077bb7812 100644
--- a/src/murmur/Server.cpp
+++ b/src/murmur/Server.cpp
@@ -75,7 +75,6 @@ QSslSocket *SslServer::nextPendingSSLConnection() {
}
User::User(Server *p, QSslSocket *socket) : Connection(p, socket), Player() {
- uiAddress = 0;
usPort = 0;
}
@@ -90,9 +89,9 @@ Server::Server(int snum, QObject *p) : QThread(p) {
connect(qtsServer, SIGNAL(newConnection()), this, SLOT(newClient()), Qt::QueuedConnection);
if (! qtsServer->listen(qhaBind, iPort))
- qFatal("Server: TCP Listen on port %d failed",iPort);
+ log("Server: TCP Listen on port %d failed",iPort);
- log(QString("Server listening on port %1").arg(iPort));
+ log("Server listening on port %d",iPort);
for (int i=1;i<5000;i++)
qqIds.enqueue(i);
@@ -139,12 +138,12 @@ void Server::readParams() {
}
}
if ((qhaBind == QHostAddress::Any) || (qhaBind.isNull())) {
- qWarning("Lookup of bind hostname %s failed", qPrintable(qsHost));
+ log("Lookup of bind hostname %s failed", qPrintable(qsHost));
qhaBind = Meta::mp.qhaBind;
}
}
- qDebug("Binding to address %s", qPrintable(qhaBind.toString()));
+ log("Binding to address %s", qPrintable(qhaBind.toString()));
}
qsPassword = getConf("password", qsPassword).toString();
@@ -186,15 +185,15 @@ int BandwidthRecord::bytesPerSec() {
}
void Server::run() {
- qDebug("Starting UDP Thread");
+ log("Starting UDP Thread");
qusUdp = new QUdpSocket();
if (! qusUdp->bind(qhaBind, iPort, QUdpSocket::DontShareAddress))
- qFatal("Server: UDP Bind to port %d failed",iPort);
+ log("Server: UDP Bind to port %d failed",iPort);
#ifdef Q_OS_UNIX
int val = IPTOS_PREC_FLASHOVERRIDE | IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
if (setsockopt(qusUdp->socketDescriptor(), IPPROTO_IP, IP_TOS, &val, sizeof(val)))
- qWarning("Server: Failed to set TOS for UDP Socket");
+ log("Server: Failed to set TOS for UDP Socket");
#endif
connect(this, SIGNAL(tcpTransmit(QByteArray, unsigned int)), this, SLOT(tcpTransmitData(QByteArray, unsigned int)), Qt::QueuedConnection);
@@ -206,8 +205,6 @@ void Server::run() {
quint32 msgType;
int uiSession;
- qDebug("Entering UDP event loop");
-
while (qusUdp->waitForReadyRead(-1)) {
QReadLocker rl(&qrwlUsers);
while (qusUdp->hasPendingDatagrams()) {
@@ -222,26 +219,17 @@ void Server::run() {
if (! pds.isValid())
continue;
- Peer p(senderAddr.toIPv4Address(), senderPort);
+ User *u = qhUsers.value(uiSession);
+ if (! u)
+ continue;
- if (p != qhPeers.value(uiSession)) {
- Connection *source = qhUsers.value(uiSession);
- if (! source || !(source->peerAddress() == senderAddr)) {
+ if ((senderAddr != u->qha) || (senderPort != u->usPort)) {
+ if (u->usPort != 0)
continue;
- }
- // At any point after this, the connection might go away WHILE we're processing. That is "bad".
- rl.unlock();
- {
- QWriteLocker wl(&qrwlUsers);
- if (qhUsers.contains(uiSession)) {
- qhHosts[uiSession] = senderAddr;
- qhPeers[uiSession] = p;
- }
- }
- rl.relock();
- if (! qhUsers.contains(uiSession)) {
+ if (u->peerAddress() != senderAddr)
continue;
- }
+ u->qha = senderAddr;
+ u->usPort = senderPort;
}
if (msgType == Message::Ping)
@@ -268,13 +256,13 @@ void Server::fakeUdpPacket(Message *msg, Connection *source) {
processMsg(pds, source);
}
-void Server::sendMessage(unsigned int id, const char *data, int len, QByteArray &cache) {
- if (qhPeers.contains(id)) {
- qusUdp->writeDatagram(data, len, qhHosts[id], qhPeers[id].second);
+void Server::sendMessage(User *u, const char *data, int len, QByteArray &cache) {
+ if (u->usPort != 0) {
+ qusUdp->writeDatagram(data, len, u->qha, u->usPort);
} else {
if (cache.isEmpty())
cache = QByteArray(data, len);
- emit tcpTransmit(cache,id);
+ emit tcpTransmit(cache,u->uiSession);
}
}
@@ -313,13 +301,13 @@ void Server::processMsg(PacketDataStream &pds, Connection *cCon) {
int len = pds.left();
if (flags & MessageSpeex::LoopBack) {
- sendMessage(u->uiSession, data, len, qba);
+ sendMessage(u, data, len, qba);
return;
}
foreach(p, c->qlPlayers) {
if (! p->bDeaf && ! p->bSelfDeaf && (p != static_cast<Player *>(u)))
- sendMessage(p->uiSession, data, len, qba);
+ sendMessage(static_cast<User *>(p), data, len, qba);
}
if (! c->qhLinks.isEmpty()) {
@@ -332,29 +320,36 @@ void Server::processMsg(PacketDataStream &pds, Connection *cCon) {
if (ChanACL::hasPermission(u, l, (flags & MessageSpeex::AltSpeak) ? ChanACL::AltSpeak : ChanACL::Speak, acCache)) {
foreach(p, l->qlPlayers) {
if (! p->bDeaf && ! p->bSelfDeaf)
- sendMessage(p->uiSession, data, len, qba);
+ sendMessage(static_cast<User *>(p), data, len, qba);
}
}
}
}
}
+void Server::log(User *u, const char *format, ...) {
+ char buffer[4096];
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, 4096, format, ap);
+ va_end(ap);
+ char fin[4096];
+ snprintf(fin, 4096, "<%d:%s(%d)> %s", u->uiSession, qPrintable(u->qsName), u->iId, buffer);
-void Server::log(QString s, Connection *c) {
- if (c) {
- User *u = static_cast<User *>(c);
-
- int id = 0;
- int iid = -1;
- QString name;
- id = u->uiSession;
- iid = u->iId;
- name = u->qsName;
- qWarning("<%d:%s(%d)> %s", id, qPrintable(name), iid, qPrintable(s));
- } else {
- qWarning("%s", qPrintable(s));
- }
+ dblog(fin);
+ qWarning("%d => %s", iServerNum, fin);
+}
+
+void Server::log(const char *format, ...) {
+ char buffer[4096];
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, 4096, format, ap);
+ va_end(ap);
+
+ dblog(buffer);
+ qWarning("%d => %s", iServerNum, buffer);
}
void Server::newClient() {
@@ -366,14 +361,22 @@ void Server::newClient() {
QHostAddress adr = sock->peerAddress();
quint32 base = adr.toIPv4Address();
+ if (meta.banCheck(adr)) {
+ log("Ignoring connection: %s:%d (Global ban)",qPrintable(sock->peerAddress().toString()),sock->peerPort());
+ sock->disconnectFromHost();
+ sock->deleteLater();
+ return;
+ }
+
QPair<quint32,int> ban;
foreach(ban, qlBans) {
int mask = 32 - ban.second;
mask = (1 << mask) - 1;
if ((base & ~mask) == (ban.first & ~mask)) {
- log(QString("Ignoring connection: %1:%2").arg(sock->peerAddress().toString()).arg(sock->peerPort()));
+ log("Ignoring connection: %s:%d",qPrintable(sock->peerAddress().toString()),sock->peerPort());
sock->disconnectFromHost();
+ sock->deleteLater();
return;
}
}
@@ -398,7 +401,7 @@ void Server::newClient() {
connect(u, SIGNAL(message(QByteArray &)), this, SLOT(message(QByteArray &)));
connect(u, SIGNAL(handleSslErrors(const QList<QSslError> &)), this, SLOT(sslError(const QList<QSslError> &)));
- log(QString("New connection: %1:%2").arg(sock->peerAddress().toString()).arg(sock->peerPort()), u);
+ log(u, "New connection: %s:%d",qPrintable(sock->peerAddress().toString()),sock->peerPort());
sock->startServerEncryption();
}
@@ -424,7 +427,7 @@ void Server::connectionClosed(QString reason) {
Connection *c = dynamic_cast<Connection *>(sender());
User *u = static_cast<User *>(c);
- log(QString("Connection closed: %1").arg(reason), c);
+ log(u, "Connection closed: %s", qPrintable(reason));
if (u->sState == Player::Authenticated) {
MessageServerLeave mslMsg;
@@ -446,7 +449,7 @@ void Server::connectionClosed(QString reason) {
qhUserTextureCache.remove(u->iId);
if (u->sState == Player::Authenticated)
- clearACLCache();
+ clearACLCache(u);
u->deleteLater();
}
@@ -478,7 +481,7 @@ void Server::checkTimeout() {
qrwlUsers.lockForRead();
foreach(User *u, qhUsers) {
if (u->activityTime() > (iTimeout * 1000)) {
- log(QLatin1String("Timeout"), u);
+ log(u, "Timeout");
qlClose.append(u);
}
}
@@ -556,6 +559,8 @@ void Server::removeChannel(Channel *chan, Player *src, Channel *dest) {
}
void Server::playerEnterChannel(Player *p, Channel *c, bool quiet) {
+ clearACLCache(p);
+
if (quiet && (p->cChannel == c))
return;
@@ -592,10 +597,16 @@ bool Server::hasPermission(Player *p, Channel *c, ChanACL::Perm perm) {
return ChanACL::hasPermission(p, c, perm, acCache);
}
-void Server::clearACLCache() {
+void Server::clearACLCache(Player *p) {
QMutexLocker qml(&qmCache);
- foreach(ChanACL::ChanCache *h, acCache)
- delete h;
- acCache.clear();
+ if (p) {
+ ChanACL::ChanCache *h = acCache.take(p);
+ if (h)
+ delete h;
+ } else {
+ foreach(ChanACL::ChanCache *h, acCache)
+ delete h;
+ acCache.clear();
+ }
}
diff --git a/src/murmur/Server.h b/src/murmur/Server.h
index 3111ec423..7bcc5b9ce 100644
--- a/src/murmur/Server.h
+++ b/src/murmur/Server.h
@@ -88,9 +88,8 @@ class User : public Connection, public Player {
Server *s;
public:
BandwidthRecord bwr;
- quint32 uiAddress;
- quint16 usPort;
QHostAddress qha;
+ quint16 usPort;
User(Server *parent, QSslSocket *socket);
};
@@ -119,7 +118,6 @@ class Server : public QThread, public MessageHandler {
void readParams();
// Registration, implementation in Register.cpp
- protected:
QTimer qtTick;
QHttp *http;
void initRegister();
@@ -129,33 +127,30 @@ class Server : public QThread, public MessageHandler {
void abort();
// Certificate stuff, implemented partially in Cert.cpp
- protected:
+ public:
void initializeCert();
const QString getDigest() const;
- protected:
- QQueue<int> qqIds;
- SslServer *qtsServer;
- QTimer *qtTimeout;
- protected slots:
+
+ public slots:
void newClient();
void connectionClosed(QString);
void sslError(const QList<QSslError> &);
void message(QByteArray &, Connection *cCon = NULL);
void checkTimeout();
void tcpTransmitData(QByteArray, unsigned int);
+ signals:
+ void tcpTransmit(QByteArray, unsigned int id);
public:
int iServerNum;
-
+ QQueue<int> qqIds;
+ SslServer *qtsServer;
+ QTimer *qtTimeout;
+ QUdpSocket *qusUdp;
QHash<unsigned int, User *> qhUsers;
QHash<unsigned int, Channel *> qhChannels;
QReadWriteLock qrwlUsers;
-
ChanACL::ACLCache acCache;
QMutex qmCache;
-
- bool hasPermission(Player *p, Channel *c, ChanACL::Perm perm);
- void clearACLCache();
-
MurmurDBus *dbus;
QHash<int, QByteArray> qhUserTextureCache;
@@ -164,20 +159,26 @@ class Server : public QThread, public MessageHandler {
QList<QPair<quint32, int> > qlBans;
+ void processMsg(PacketDataStream &pds, Connection *cCon);
+ void sendMessage(User *u, const char *data, int len, QByteArray &cache);
+ void fakeUdpPacket(Message *msg, Connection *source);
+ void run();
+
+ bool hasPermission(Player *p, Channel *c, ChanACL::Perm perm);
+ void clearACLCache(Player *p = NULL);
+
void sendAll(Message *);
void sendExcept(Message *, Connection *);
void sendMessage(unsigned int, Message *);
void sendMessage(Connection *, Message *);
- void log(QString s, Connection *c = NULL);
+// void log(QString s, Connection *c = NULL);
+ __attribute__((format(printf, 2, 3))) void log(const char *format, ...);
+ __attribute__((format(printf, 3, 4))) void log(User *u, const char *format, ...);
void removeChannel(Channel *c, Player *src, Channel *dest = NULL);
void playerEnterChannel(Player *u, Channel *c, bool quiet = false);
- void emitPacket(Message *msg);
-
- User *getUser(unsigned int);
-
Server(int snum, QObject *parent = NULL);
~Server();
@@ -203,6 +204,7 @@ class Server : public QThread, public MessageHandler {
void saveBans();
QVariant getConf(const QString &key, QVariant def);
void setConf(const QString &key, const QVariant &value);
+ void dblog(const char *str);
// From msgHandler. Implementation in Messages.cpp
virtual void msgSpeex(Connection *, MessageSpeex *);
@@ -230,18 +232,6 @@ class Server : public QThread, public MessageHandler {
virtual void msgQueryUsers(Connection *, MessageQueryUsers *);
virtual void msgTexture(Connection *, MessageTexture *);
- // UDP Handling
- protected:
- QUdpSocket *qusUdp;
- QHash<unsigned int, Peer> qhPeers;
- QHash<unsigned int, QHostAddress> qhHosts;
- void processMsg(PacketDataStream &pds, Connection *cCon);
- void sendMessage(unsigned int id, const char *data, int len, QByteArray &cache);
- signals:
- void tcpTransmit(QByteArray, unsigned int id);
- public:
- void fakeUdpPacket(Message *msg, Connection *source);
- void run();
};
diff --git a/src/murmur/ServerDB.cpp b/src/murmur/ServerDB.cpp
index 73c97a6cf..edf46d976 100644
--- a/src/murmur/ServerDB.cpp
+++ b/src/murmur/ServerDB.cpp
@@ -107,7 +107,7 @@ ServerDB::ServerDB() {
}
if (found) {
QFileInfo fi(db.databaseName());
- qDebug("Openend SQLite database %s", qPrintable(fi.absoluteFilePath()));
+ qWarning("Openend SQLite database %s", qPrintable(fi.absoluteFilePath()));
}
} else {
db.setDatabaseName(Meta::mp.qsDatabase);
@@ -147,8 +147,13 @@ ServerDB::ServerDB() {
}
SQLDO("CREATE TABLE %1meta (key TEXT PRIMARY KEY, value TEXT)");
SQLDO("CREATE TABLE %1servers (server_id INTEGER PRIMARY KEY AUTOINCREMENT)");
+
+ SQLDO("CREATE TABLE %1log(server_id INTEGER, msg TEXT, msgtime DATE)");
+ SQLDO("CREATE TRIGGER %1log_timestamp AFTER INSERT ON %1log FOR EACH ROW BEGIN UPDATE %1log SET msgtime = datetime('now') WHERE rowid = new.rowid; END;");
+
SQLDO("CREATE TABLE %1config (server_id INTEGER, key TEXT, value TEXT)");
SQLDO("CREATE UNIQUE INDEX %1config_key ON %1config(server_id, key)");
+ SQLDO("CREATE TRIGGER %1config_server_del AFTER DELETE ON %1servers FOR EACH ROW BEGIN DELETE FROM %1config WHERE server_id = old.server_id; END;");
SQLDO("CREATE TABLE %1players (server_id INTEGER, player_id INTEGER, name TEXT, email TEXT, pw TEXT, lastchannel INTEGER, texture BLOB, last_active DATE)");
SQLDO("CREATE UNIQUE INDEX %1players_name ON %1players (server_id,name)");
@@ -187,7 +192,7 @@ ServerDB::ServerDB() {
SQLDO("INSERT INTO %1meta (key, value) VALUES('version','1')");
if (migrate) {
- qDebug("Migrating from single-server database to multi-server database");
+ qWarning("Migrating from single-server database to multi-server database");
SQLDO("INSERT INTO %1players SELECT 1, player_id, name, email, pw, lastchannel, texture, null FROM playersold");
SQLDO("INSERT INTO %1channels SELECT 1, channel_id, parent_id, name, inheritACL FROM channelsold");
SQLDO("INSERT INTO %1groups SELECT group_id, 1, name, channel_id, inherit, inheritable FROM groupsold");
@@ -570,7 +575,7 @@ void Server::readChannelPrivs(Channel *c) {
g->bInheritable = query.value(3).toBool();
QSqlQuery mem;
- mem.prepare("SELECT player_id, addit FROM %1group_members WHERE group_id = ?");
+ mem.prepare(QString::fromLatin1("SELECT player_id, addit FROM %1group_members WHERE group_id = ?").arg(Meta::mp.qsDBPrefix));
mem.addBindValue(gid);
mem.exec();
while (mem.next()) {
@@ -754,6 +759,15 @@ void Server::setConf(const QString &key, const QVariant &value) {
ServerDB::setConf(iServerNum, key, value);
}
+void Server::dblog(const char *str) {
+ TransactionHolder th;
+ QSqlQuery query;
+ SQLPREP("INSERT INTO %1log (server_id, msg) VALUES(?,?)");
+ query.addBindValue(iServerNum);
+ query.addBindValue(QLatin1String(str));
+ SQLEXEC();
+}
+
void ServerDB::setConf(int server_id, const QString &key, const QVariant &value) {
TransactionHolder th;
diff --git a/src/murmur/murmur.cpp b/src/murmur/murmur.cpp
index b80cf4924..012d438d2 100644
--- a/src/murmur/murmur.cpp
+++ b/src/murmur/murmur.cpp
@@ -56,6 +56,8 @@ bool detach = true;
bool detach = false;
#endif
+Meta meta;
+
LogEmitter le;
static void murmurMessageOutput(QtMsgType type, const char *msg) {
@@ -219,8 +221,6 @@ int main(int argc, char **argv) {
MurmurDBus::registerTypes();
#endif
- Meta m;
-
#ifdef Q_OS_UNIX
if (! Meta::mp.qsDBus.isEmpty()) {
QDBusConnection qdbc("mainbus");
@@ -244,13 +244,13 @@ int main(int argc, char **argv) {
qWarning("Failed to connect to D-Bus %s",qPrintable(Meta::mp.qsDBus));
}
MurmurDBus::qdbc = qdbc;
- new MetaDBus(&m);
- qdbc.registerObject("/", &m);
+ new MetaDBus(&meta);
+ qdbc.registerObject("/", &meta);
qdbc.registerService("net.sourceforge.mumble.murmur");
}
#endif
- m.bootAll();
+ meta.bootAll();
res=a.exec();