1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #include "murmur_pch.h"
7 
8 #include "Meta.h"
9 
10 #include "Connection.h"
11 #include "Net.h"
12 #include "ServerDB.h"
13 #include "Server.h"
14 #include "OSInfo.h"
15 #include "Version.h"
16 #include "SSL.h"
17 #include "EnvUtils.h"
18 #include "FFDHE.h"
19 
20 #if defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
21 # include <QSslDiffieHellmanParameters>
22 #endif
23 
24 MetaParams Meta::mp;
25 
26 #ifdef Q_OS_WIN
27 HANDLE Meta::hQoS = NULL;
28 #endif
29 
MetaParams()30 MetaParams::MetaParams() {
31 	qsPassword = QString();
32 	usPort = DEFAULT_MUMBLE_PORT;
33 	iTimeout = 30;
34 	iMaxBandwidth = 72000;
35 	iMaxUsers = 1000;
36 	iMaxUsersPerChannel = 0;
37 	iMaxTextMessageLength = 5000;
38 	iMaxImageMessageLength = 131072;
39 	legacyPasswordHash = false;
40 	kdfIterations = -1;
41 	bAllowHTML = true;
42 	iDefaultChan = 0;
43 	bRememberChan = true;
44 	qsWelcomeText = QString();
45 	qsDatabase = QString();
46 	iSQLiteWAL = 0;
47 	iDBPort = 0;
48 	qsDBusService = "net.sourceforge.mumble.murmur";
49 	qsDBDriver = "QSQLITE";
50 	qsLogfile = "murmur.log";
51 
52 	iLogDays = 31;
53 
54 	iObfuscate = 0;
55 	bSendVersion = true;
56 	bBonjour = true;
57 	bAllowPing = true;
58 	bCertRequired = false;
59 	bForceExternalAuth = false;
60 
61 	iBanTries = 10;
62 	iBanTimeframe = 120;
63 	iBanTime = 300;
64 
65 #ifdef Q_OS_UNIX
66 	uiUid = uiGid = 0;
67 #endif
68 
69 	iOpusThreshold = 100;
70 
71 	iChannelNestingLimit = 10;
72 	iChannelCountLimit = 1000;
73 
74 	qrUserName = QRegExp(QLatin1String("[-=\\w\\[\\]\\{\\}\\(\\)\\@\\|\\.]+"));
75 	qrChannelName = QRegExp(QLatin1String("[ \\-=\\w\\#\\[\\]\\{\\}\\(\\)\\@\\|]+"));
76 
77 	iMessageLimit = 1;
78 	iMessageBurst = 5;
79 
80 	qsCiphers = MumbleSSL::defaultOpenSSLCipherString();
81 
82 	qsSettings = NULL;
83 }
84 
~MetaParams()85 MetaParams::~MetaParams() {
86 	delete qsSettings;
87 }
88 
89 /**
90  *	Checks whether a qsSettings config variable named 'name' was set to a valid value for the type
91  *  we want to convert it to. Otherwise a error message is logged and 'defaultValue' is returned.
92  *
93  *  E.g. checkedFromSettings<QString>("blub", bla) would output an error message and leave bla unchanged
94  *		 if the user had set the ini parameter to "blub = has, commas, in, it" which QSettings will interpret
95  *		 not as a String but as a list of strings.
96  *
97  *	@param T Conversion target type (type of 'defaultValue', auto inducable)
98  *	@param name qsSettings variable name
99  *	@param defaultValue Default value for 'name'
100  *	@param settings The QSettings object to read from. If null, the Meta's qsSettings will be used.
101  *	@return Setting if valid, default if not or setting not set.
102  */
103 template <class T>
typeCheckedFromSettings(const QString & name,const T & defaultValue,QSettings * settings)104 T MetaParams::typeCheckedFromSettings(const QString &name, const T &defaultValue, QSettings *settings) {
105 	// Use qsSettings unless a specific QSettings instance
106 	// is requested.
107 	if (settings == NULL) {
108 		settings = qsSettings;
109 	}
110 
111 	QVariant cfgVariable = settings->value(name, defaultValue);
112 
113 	if (!cfgVariable.convert(QVariant(defaultValue).type())) { // Bit convoluted as canConvert<T>() only does a static check without considering whether say a string like "blub" is actually a valid double (which convert does).
114 		qCritical() << "Configuration variable" << name << "is of invalid format. Set to default value of" << defaultValue << ".";
115 		return defaultValue;
116 	}
117 
118 	return cfgVariable.value<T>();
119 }
120 
read(QString fname)121 void MetaParams::read(QString fname) {
122 	qmConfig.clear();
123 
124 	if (fname.isEmpty()) {
125 		QStringList datapaths;
126 
127 #if defined(Q_OS_WIN)
128 #if QT_VERSION >= 0x050000
129 		datapaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation);
130 #else
131 		datapaths << QDesktopServices::storageLocation(QDesktopServices::DataLocation);
132 #endif
133 
134 		QDir appdir = QDir(QDir::fromNativeSeparators(EnvUtils::getenv(QLatin1String("APPDATA"))));
135 		datapaths << appdir.absolutePath() + QLatin1String("/Mumble");
136 #else
137 		datapaths << QDir::homePath() + QLatin1String("/.murmurd");
138 		datapaths << QDir::homePath() + QLatin1String("/.config/Mumble");
139 #endif
140 
141 #if defined(Q_OS_MAC)
142 		/* Old Mac data path. */
143 		datapaths << QDir::homePath() + QLatin1String("/Library/Preferences/Mumble/");
144 #endif
145 
146 		datapaths << QDir::homePath();
147 		datapaths << QDir::currentPath();
148 		datapaths << QCoreApplication::instance()->applicationDirPath();
149 
150 		foreach(const QString &p, datapaths) {
151 			if (! p.isEmpty()) {
152 				QFileInfo fi(p, "murmur.ini");
153 				if (fi.exists() && fi.isReadable()) {
154 					qdBasePath = QDir(p);
155 					qsAbsSettingsFilePath = fi.absoluteFilePath();
156 					break;
157 				}
158 			}
159 		}
160 		if (qsAbsSettingsFilePath.isEmpty()) {
161 			QDir::root().mkpath(qdBasePath.absolutePath());
162 			qdBasePath = QDir(datapaths.at(0));
163 			qsAbsSettingsFilePath = qdBasePath.absolutePath() + QLatin1String("/murmur.ini");
164 		}
165 	} else {
166 		QFile f(fname);
167 		if (! f.open(QIODevice::ReadOnly)) {
168 			qFatal("Specified ini file %s could not be opened", qPrintable(fname));
169 		}
170 		qdBasePath = QFileInfo(f).absoluteDir();
171 		qsAbsSettingsFilePath = QFileInfo(f).absoluteFilePath();
172 		f.close();
173 	}
174 	QDir::setCurrent(qdBasePath.absolutePath());
175 	qsSettings = new QSettings(qsAbsSettingsFilePath, QSettings::IniFormat);
176 #if QT_VERSION >= 0x040500
177 	qsSettings->setIniCodec("UTF-8");
178 #endif
179 	qWarning("Initializing settings from %s (basepath %s)", qPrintable(qsSettings->fileName()), qPrintable(qdBasePath.absolutePath()));
180 
181 	QString qsHost = qsSettings->value("host", QString()).toString();
182 	if (! qsHost.isEmpty()) {
183 		foreach(const QString &host, qsHost.split(QRegExp(QLatin1String("\\s+")), QString::SkipEmptyParts)) {
184 			QHostAddress qhaddr;
185 			if (qhaddr.setAddress(host)) {
186 				qlBind << qhaddr;
187 			} else {
188 				bool found = false;
189 				QHostInfo hi = QHostInfo::fromName(host);
190 				foreach(QHostAddress qha, hi.addresses()) {
191 					if ((qha.protocol() == QAbstractSocket::IPv4Protocol) || (qha.protocol() == QAbstractSocket::IPv6Protocol)) {
192 						qlBind << qha;
193 						found = true;
194 					}
195 				}
196 				if (! found) {
197 					qFatal("Lookup of bind hostname %s failed", qPrintable(host));
198 				}
199 			}
200 		}
201 		foreach(const QHostAddress &qha, qlBind)
202 			qWarning("Binding to address %s", qPrintable(qha.toString()));
203 	}
204 
205 	if (qlBind.isEmpty()) {
206 		bool hasipv6 = false;
207 		bool hasipv4 = false;
208 		int nif = 0;
209 
210 		QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
211 		if (interfaces.isEmpty()) {
212 			qWarning("Meta: Unable to acquire list of network interfaces.");
213 		} else {
214 			foreach(const QNetworkInterface &qni, interfaces) {
215 				if (!(qni.flags() & QNetworkInterface::IsUp))
216 					continue;
217 				if (!(qni.flags() & QNetworkInterface::IsRunning))
218 					continue;
219 				if (qni.flags() & QNetworkInterface::IsLoopBack)
220 					continue;
221 
222 				foreach(const QNetworkAddressEntry &qna, qni.addressEntries()) {
223 					const QHostAddress &qha = qna.ip();
224 					switch (qha.protocol()) {
225 						case QAbstractSocket::IPv4Protocol:
226 							hasipv4 = true;
227 							break;
228 						case QAbstractSocket::IPv6Protocol:
229 							hasipv6 = true;
230 							break;
231 						default:
232 							break;
233 					}
234 				}
235 
236 				++nif;
237 			}
238 		}
239 
240 		if (nif == 0) {
241 			qWarning("Meta: Could not determine IPv4/IPv6 support via network interfaces, assuming support for both.");
242 			hasipv6 = true;
243 			hasipv4 = true;
244 		}
245 
246 #if QT_VERSION >= 0x050000
247 		if (hasipv6) {
248 			if (SslServer::hasDualStackSupport() && hasipv4) {
249 				qlBind << QHostAddress(QHostAddress::Any);
250 				hasipv4 = false; // No need to add a separate ipv4 socket
251 			} else {
252 				qlBind << QHostAddress(QHostAddress::AnyIPv6);
253 			}
254 		}
255 
256 		if (hasipv4) {
257 			qlBind << QHostAddress(QHostAddress::AnyIPv4);
258 		}
259 #else // QT_VERSION < 0x050000
260 		// For Qt 4 AnyIPv6 resulted in a dual stack socket on dual stack
261 		// capable systems while Any resulted in an IPv4 only socket. For
262 		// Qt 5 this has been reworked so that AnyIPv6/v4 are now exclusive
263 		// IPv6/4 sockets while Any is the dual stack socket.
264 
265 		if (hasipv6) {
266 			qlBind << QHostAddress(QHostAddress::AnyIPv6);
267 			if (SslServer::hasDualStackSupport() && hasipv4) {
268 				hasipv4 = false; // No need to add a separate ipv4 socket
269 			}
270 		}
271 
272 		if (hasipv4) {
273 			qlBind << QHostAddress(QHostAddress::Any);
274 		}
275 #endif
276 	}
277 
278 	qsPassword = typeCheckedFromSettings("serverpassword", qsPassword);
279 	usPort = static_cast<unsigned short>(typeCheckedFromSettings("port", static_cast<uint>(usPort)));
280 	iTimeout = typeCheckedFromSettings("timeout", iTimeout);
281 	iMaxTextMessageLength = typeCheckedFromSettings("textmessagelength", iMaxTextMessageLength);
282 	iMaxImageMessageLength = typeCheckedFromSettings("imagemessagelength", iMaxImageMessageLength);
283 	legacyPasswordHash = typeCheckedFromSettings("legacypasswordhash", legacyPasswordHash);
284 	kdfIterations = typeCheckedFromSettings("kdfiterations", -1);
285 	bAllowHTML = typeCheckedFromSettings("allowhtml", bAllowHTML);
286 	iMaxBandwidth = typeCheckedFromSettings("bandwidth", iMaxBandwidth);
287 	iDefaultChan = typeCheckedFromSettings("defaultchannel", iDefaultChan);
288 	bRememberChan = typeCheckedFromSettings("rememberchannel", bRememberChan);
289 	iMaxUsers = typeCheckedFromSettings("users", iMaxUsers);
290 	iMaxUsersPerChannel = typeCheckedFromSettings("usersperchannel", iMaxUsersPerChannel);
291 	qsWelcomeText = typeCheckedFromSettings("welcometext", qsWelcomeText);
292 	bCertRequired = typeCheckedFromSettings("certrequired", bCertRequired);
293 	bForceExternalAuth = typeCheckedFromSettings("forceExternalAuth", bForceExternalAuth);
294 
295 	qsDatabase = typeCheckedFromSettings("database", qsDatabase);
296 	iSQLiteWAL = typeCheckedFromSettings("sqlite_wal", iSQLiteWAL);
297 
298 	qsDBDriver = typeCheckedFromSettings("dbDriver", qsDBDriver);
299 	qsDBUserName = typeCheckedFromSettings("dbUsername", qsDBUserName);
300 	qsDBPassword = typeCheckedFromSettings("dbPassword", qsDBPassword);
301 	qsDBHostName = typeCheckedFromSettings("dbHost", qsDBHostName);
302 	qsDBPrefix = typeCheckedFromSettings("dbPrefix", qsDBPrefix);
303 	qsDBOpts = typeCheckedFromSettings("dbOpts", qsDBOpts);
304 	iDBPort = typeCheckedFromSettings("dbPort", iDBPort);
305 
306 	qsIceEndpoint = typeCheckedFromSettings("ice", qsIceEndpoint);
307 	qsIceSecretRead = typeCheckedFromSettings("icesecret", qsIceSecretRead);
308 	qsIceSecretRead = typeCheckedFromSettings("icesecretread", qsIceSecretRead);
309 	qsIceSecretWrite = typeCheckedFromSettings("icesecretwrite", qsIceSecretRead);
310 
311 	qsGRPCAddress = typeCheckedFromSettings("grpc", qsGRPCAddress);
312 	qsGRPCCert = typeCheckedFromSettings("grpccert", qsGRPCCert);
313 	qsGRPCKey = typeCheckedFromSettings("grpckey", qsGRPCKey);
314 
315 	iLogDays = typeCheckedFromSettings("logdays", iLogDays);
316 
317 	qsDBus = typeCheckedFromSettings("dbus", qsDBus);
318 	qsDBusService = typeCheckedFromSettings("dbusservice", qsDBusService);
319 	qsLogfile = typeCheckedFromSettings("logfile", qsLogfile);
320 	qsPid = typeCheckedFromSettings("pidfile", qsPid);
321 
322 	qsRegName = typeCheckedFromSettings("registerName", qsRegName);
323 	qsRegPassword = typeCheckedFromSettings("registerPassword", qsRegPassword);
324 	qsRegHost = typeCheckedFromSettings("registerHostname", qsRegHost);
325 	qsRegLocation = typeCheckedFromSettings("registerLocation", qsRegLocation);
326 	qurlRegWeb = QUrl(typeCheckedFromSettings("registerUrl", qurlRegWeb).toString());
327 	bBonjour = typeCheckedFromSettings("bonjour", bBonjour);
328 
329 	iBanTries = typeCheckedFromSettings("autobanAttempts", iBanTries);
330 	iBanTimeframe = typeCheckedFromSettings("autobanTimeframe", iBanTimeframe);
331 	iBanTime = typeCheckedFromSettings("autobanTime", iBanTime);
332 
333 	qvSuggestVersion = MumbleVersion::getRaw(qsSettings->value("suggestVersion").toString());
334 	if (qvSuggestVersion.toUInt() == 0)
335 		qvSuggestVersion = QVariant();
336 
337 	qvSuggestPositional = qsSettings->value("suggestPositional");
338 	if (qvSuggestPositional.toString().trimmed().isEmpty())
339 		qvSuggestPositional = QVariant();
340 
341 	qvSuggestPushToTalk = qsSettings->value("suggestPushToTalk");
342 	if (qvSuggestPushToTalk.toString().trimmed().isEmpty())
343 		qvSuggestPushToTalk = QVariant();
344 
345 	iOpusThreshold = typeCheckedFromSettings("opusthreshold", iOpusThreshold);
346 
347 	iChannelNestingLimit = typeCheckedFromSettings("channelnestinglimit", iChannelNestingLimit);
348 	iChannelCountLimit = typeCheckedFromSettings("channelcountlimit", iChannelCountLimit);
349 
350 #ifdef Q_OS_UNIX
351 	qsName = qsSettings->value("uname").toString();
352 	if (geteuid() == 0) {
353 		// TODO: remove this silent fallback to enforce running as non-root
354 		bool requested = true;
355 		if (qsName.isEmpty()) {
356 			// default server user name
357 			qsName = "mumble-server";
358 			requested = false;
359 		}
360 		struct passwd *pw = getpwnam(qPrintable(qsName));
361 		if (pw) {
362 			uiUid = pw->pw_uid;
363 			uiGid = pw->pw_gid;
364 			qsHome = pw->pw_dir;
365 		} else if (requested) {
366 			qFatal("Cannot find username %s", qPrintable(qsName));
367 		}
368 		endpwent();
369 	}
370 #endif
371 
372 	qrUserName = QRegExp(typeCheckedFromSettings("username", qrUserName.pattern()));
373 	qrChannelName = QRegExp(typeCheckedFromSettings("channelname", qrChannelName.pattern()));
374 
375 	iMessageLimit = typeCheckedFromSettings("messagelimit", 1);
376 	iMessageBurst = typeCheckedFromSettings("messageburst", 5);
377 
378 	bool bObfuscate = typeCheckedFromSettings("obfuscate", false);
379 	if (bObfuscate) {
380 		qWarning("IP address obfuscation enabled.");
381 		iObfuscate = qrand();
382 	}
383 	bSendVersion = typeCheckedFromSettings("sendversion", bSendVersion);
384 	bAllowPing = typeCheckedFromSettings("allowping", bAllowPing);
385 
386 	if (!loadSSLSettings()) {
387 		qFatal("MetaParams: Failed to load SSL settings. See previous errors.");
388 	}
389 
390 	QStringList hosts;
391 	foreach(const QHostAddress &qha, qlBind) {
392 		hosts << qha.toString();
393 	}
394 	qmConfig.insert(QLatin1String("host"),hosts.join(" "));
395 	qmConfig.insert(QLatin1String("password"),qsPassword);
396 	qmConfig.insert(QLatin1String("port"),QString::number(usPort));
397 	qmConfig.insert(QLatin1String("timeout"),QString::number(iTimeout));
398 	qmConfig.insert(QLatin1String("textmessagelength"), QString::number(iMaxTextMessageLength));
399 	qmConfig.insert(QLatin1String("legacypasswordhash"), legacyPasswordHash ?  QLatin1String("true") : QLatin1String("false"));
400 	qmConfig.insert(QLatin1String("kdfiterations"), QString::number(kdfIterations));
401 	qmConfig.insert(QLatin1String("allowhtml"), bAllowHTML ? QLatin1String("true") : QLatin1String("false"));
402 	qmConfig.insert(QLatin1String("bandwidth"),QString::number(iMaxBandwidth));
403 	qmConfig.insert(QLatin1String("users"),QString::number(iMaxUsers));
404 	qmConfig.insert(QLatin1String("defaultchannel"),QString::number(iDefaultChan));
405 	qmConfig.insert(QLatin1String("rememberchannel"),bRememberChan ? QLatin1String("true") : QLatin1String("false"));
406 	qmConfig.insert(QLatin1String("welcometext"),qsWelcomeText);
407 	qmConfig.insert(QLatin1String("registername"),qsRegName);
408 	qmConfig.insert(QLatin1String("registerpassword"),qsRegPassword);
409 	qmConfig.insert(QLatin1String("registerhostname"),qsRegHost);
410 	qmConfig.insert(QLatin1String("registerlocation"), qsRegLocation);
411 	qmConfig.insert(QLatin1String("registerurl"),qurlRegWeb.toString());
412 	qmConfig.insert(QLatin1String("bonjour"), bBonjour ? QLatin1String("true") : QLatin1String("false"));
413 	qmConfig.insert(QLatin1String("certificate"),qscCert.toPem());
414 	qmConfig.insert(QLatin1String("key"),qskKey.toPem());
415 	qmConfig.insert(QLatin1String("obfuscate"),bObfuscate ? QLatin1String("true") : QLatin1String("false"));
416 	qmConfig.insert(QLatin1String("username"),qrUserName.pattern());
417 	qmConfig.insert(QLatin1String("channelname"),qrChannelName.pattern());
418 	qmConfig.insert(QLatin1String("certrequired"), bCertRequired ? QLatin1String("true") : QLatin1String("false"));
419 	qmConfig.insert(QLatin1String("forceExternalAuth"), bForceExternalAuth ? QLatin1String("true") : QLatin1String("false"));
420 	qmConfig.insert(QLatin1String("suggestversion"), qvSuggestVersion.isNull() ? QString() : qvSuggestVersion.toString());
421 	qmConfig.insert(QLatin1String("suggestpositional"), qvSuggestPositional.isNull() ? QString() : qvSuggestPositional.toString());
422 	qmConfig.insert(QLatin1String("suggestpushtotalk"), qvSuggestPushToTalk.isNull() ? QString() : qvSuggestPushToTalk.toString());
423 	qmConfig.insert(QLatin1String("opusthreshold"), QString::number(iOpusThreshold));
424 	qmConfig.insert(QLatin1String("channelnestinglimit"), QString::number(iChannelNestingLimit));
425 	qmConfig.insert(QLatin1String("channelcountlimit"), QString::number(iChannelCountLimit));
426 	qmConfig.insert(QLatin1String("sslCiphers"), qsCiphers);
427 	qmConfig.insert(QLatin1String("sslDHParams"), QString::fromLatin1(qbaDHParams.constData()));
428 }
429 
loadSSLSettings()430 bool MetaParams::loadSSLSettings() {
431 	QSettings updatedSettings(qsAbsSettingsFilePath, QSettings::IniFormat);
432 #if QT_VERSION >= 0x040500
433 	updatedSettings.setIniCodec("UTF-8");
434 #endif
435 
436 	QString tmpCiphersStr = typeCheckedFromSettings("sslCiphers", qsCiphers);
437 
438 	QString qsSSLCert = qsSettings->value("sslCert").toString();
439 	QString qsSSLKey = qsSettings->value("sslKey").toString();
440 	QString qsSSLCA = qsSettings->value("sslCA").toString();
441 	QString qsSSLDHParams = typeCheckedFromSettings(QLatin1String("sslDHParams"), QString(QLatin1String("@ffdhe2048")));
442 
443 	qbaPassPhrase = qsSettings->value("sslPassPhrase").toByteArray();
444 
445 	QSslCertificate tmpCert;
446 	QList<QSslCertificate> tmpCA;
447 	QList<QSslCertificate> tmpIntermediates;
448 	QSslKey tmpKey;
449 	QByteArray tmpDHParams;
450 	QList<QSslCipher> tmpCiphers;
451 
452 
453 	if (! qsSSLCA.isEmpty()) {
454 		QFile pem(qsSSLCA);
455 		if (pem.open(QIODevice::ReadOnly)) {
456 			QByteArray qba = pem.readAll();
457 			pem.close();
458 			QList<QSslCertificate> ql = QSslCertificate::fromData(qba);
459 			if (ql.isEmpty()) {
460 				qCritical("MetaParams: Failed to parse any CA certificates from %s", qPrintable(qsSSLCA));
461 				return false;
462 			} else {
463 				tmpCA = ql;
464 			}
465 		} else {
466 			qCritical("MetaParams: Failed to read %s", qPrintable(qsSSLCA));
467 			return false;
468 		}
469 	}
470 
471 	QByteArray crt, key;
472 
473 	if (! qsSSLCert.isEmpty()) {
474 		QFile pem(qsSSLCert);
475 		if (pem.open(QIODevice::ReadOnly)) {
476 			crt = pem.readAll();
477 			pem.close();
478 		} else {
479 			qCritical("MetaParams: Failed to read %s", qPrintable(qsSSLCert));
480 			return false;
481 		}
482 	}
483 	if (! qsSSLKey.isEmpty()) {
484 		QFile pem(qsSSLKey);
485 		if (pem.open(QIODevice::ReadOnly)) {
486 			key = pem.readAll();
487 			pem.close();
488 		} else {
489 			qCritical("MetaParams: Failed to read %s", qPrintable(qsSSLKey));
490 			return false;
491 		}
492 	}
493 
494 	if (! key.isEmpty() || ! crt.isEmpty()) {
495 		if (! key.isEmpty()) {
496 			tmpKey = Server::privateKeyFromPEM(key, qbaPassPhrase);
497 		}
498 		if (tmpKey.isNull() && ! crt.isEmpty()) {
499 			tmpKey = Server::privateKeyFromPEM(crt, qbaPassPhrase);
500 			if (! tmpKey.isNull())
501 				qCritical("MetaParams: Using private key found in certificate file.");
502 		}
503 		if (tmpKey.isNull()) {
504 			qCritical("MetaParams: No private key found in certificate or key file.");
505 			return false;
506 		}
507 
508 		QList<QSslCertificate> ql = QSslCertificate::fromData(crt);
509 		ql << QSslCertificate::fromData(key);
510 		for (int i=0;i<ql.size(); ++i) {
511 			const QSslCertificate &c = ql.at(i);
512 			if (Server::isKeyForCert(tmpKey, c)) {
513 				tmpCert = c;
514 				ql.removeAt(i);
515 				break;
516 			}
517 		}
518 		if (tmpCert.isNull()) {
519 			qCritical("MetaParams: Failed to find certificate matching private key.");
520 			return false;
521 		}
522 		if (ql.size() > 0) {
523 			tmpIntermediates = ql;
524 			qCritical("MetaParams: Adding %d intermediate certificates from certificate file.", ql.size());
525 		}
526 	}
527 
528 	QByteArray dhparams;
529 
530 #if defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
531 	if (! qsSSLDHParams.isEmpty()) {
532 		if (qsSSLDHParams.startsWith(QLatin1String("@"))) {
533 			QString group = qsSSLDHParams.mid(1).trimmed();
534 			QByteArray pem = FFDHE::PEMForNamedGroup(group);
535 			if (pem.isEmpty()) {
536 				QStringList names = FFDHE::NamedGroups();
537 				QStringList atNames;
538 				foreach (QString name, names) {
539 					atNames << QLatin1String("@") + name;
540 				}
541 				QString supported = atNames.join(QLatin1String(", "));
542 				qFatal("MetaParms: Diffie-Hellman parameters with name '%s' is not available. (Supported: %s)", qPrintable(qsSSLDHParams), qPrintable(supported));
543 			}
544 			dhparams = pem;
545 		} else {
546 			QFile pem(qsSSLDHParams);
547 			if (pem.open(QIODevice::ReadOnly)) {
548 				dhparams = pem.readAll();
549 				pem.close();
550 			} else {
551 				qFatal("MetaParams: Failed to read %s", qPrintable(qsSSLDHParams));
552 			}
553 		}
554 	}
555 
556 	if (! dhparams.isEmpty()) {
557 		QSslDiffieHellmanParameters qdhp = QSslDiffieHellmanParameters::fromEncoded(dhparams);
558 		if (qdhp.isValid()) {
559 			tmpDHParams = dhparams;
560 		} else {
561 			qFatal("MetaParams: Unable to use specified Diffie-Hellman parameters: %s", qPrintable(qdhp.errorString()));
562 			return false;
563 		}
564 	}
565 #else
566 	QString qsSSLDHParamsIniValue = qsSettings->value(QLatin1String("sslDHParams")).toString();
567 	if (! qsSSLDHParamsIniValue.isEmpty()) {
568 		qFatal("MetaParams: This version of Murmur does not support Diffie-Hellman parameters (sslDHParams). Murmur will not start unless you remove the option from your murmur.ini file.");
569 		return false;
570 	}
571 #endif
572 
573 	{
574 		QList<QSslCipher> ciphers = MumbleSSL::ciphersFromOpenSSLCipherString(tmpCiphersStr);
575 		if (ciphers.isEmpty()) {
576 			qCritical("MetaParams: Invalid sslCiphers option. Either the cipher string is invalid or none of the ciphers are available: \"%s\"", qPrintable(qsCiphers));
577 			return false;
578 		}
579 
580 #if !defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
581 		// If the version of Qt we're building against doesn't support
582 		// QSslDiffieHellmanParameters, then we must filter out Diffie-
583 		// Hellman cipher suites in order to guarantee that we do not
584 		// use Qt's default Diffie-Hellman parameters.
585 		{
586 			QList<QSslCipher> filtered;
587 			foreach (QSslCipher c, ciphers) {
588 				if (c.keyExchangeMethod() == QLatin1String("DH")) {
589 					continue;
590 				}
591 				filtered << c;
592 			}
593 			if (ciphers.size() != filtered.size()) {
594 				qWarning("MetaParams: Warning: all cipher suites in sslCiphers using Diffie-Hellman key exchange "
595 				         "have been removed. Qt %s does not support custom Diffie-Hellman parameters.",
596 				         qVersion());
597 			}
598 
599 			tmpCiphers = filtered;
600 		}
601 #else
602 		tmpCiphers = ciphers;
603 #endif
604 
605 		QStringList pref;
606 		foreach (QSslCipher c, tmpCiphers) {
607 			pref << c.name();
608 		}
609 		qWarning("MetaParams: TLS cipher preference is \"%s\"", qPrintable(pref.join(QLatin1String(":"))));
610 	}
611 
612 	qscCert = tmpCert;
613 	qlCA = tmpCA;
614 	qlIntermediates = tmpIntermediates;
615 	qskKey = tmpKey;
616 	qbaDHParams = tmpDHParams;
617 	qsCiphers = tmpCiphersStr;
618 	qlCiphers = tmpCiphers;
619 
620 	qmConfig.insert(QLatin1String("certificate"), qscCert.toPem());
621 	qmConfig.insert(QLatin1String("key"), qskKey.toPem());
622 	qmConfig.insert(QLatin1String("sslCiphers"), qsCiphers);
623 	qmConfig.insert(QLatin1String("sslDHParams"), QString::fromLatin1(qbaDHParams.constData()));
624 
625 	return true;
626 }
627 
Meta()628 Meta::Meta() {
629 #ifdef Q_OS_WIN
630 	QOS_VERSION qvVer;
631 	qvVer.MajorVersion = 1;
632 	qvVer.MinorVersion = 0;
633 
634 	hQoS = NULL;
635 
636 	HMODULE hLib = LoadLibrary(L"qWave.dll");
637 	if (hLib == NULL) {
638 		qWarning("Meta: Failed to load qWave.dll, no QoS available");
639 	} else {
640 		FreeLibrary(hLib);
641 		if (! QOSCreateHandle(&qvVer, &hQoS))
642 			qWarning("Meta: Failed to create QOS2 handle");
643 		else
644 			Connection::setQoS(hQoS);
645 	}
646 #endif
647 }
648 
~Meta()649 Meta::~Meta() {
650 #ifdef Q_OS_WIN
651 	if (hQoS) {
652 		QOSCloseHandle(hQoS);
653 		Connection::setQoS(NULL);
654 	}
655 #endif
656 }
657 
reloadSSLSettings()658 bool Meta::reloadSSLSettings() {
659 	// Reload SSL settings.
660 	if (!Meta::mp.loadSSLSettings()) {
661 		return false;
662 	}
663 
664 	// Re-initialize certificates for all
665 	// virtual servers using the Meta server's
666 	// certificate and private key.
667 	foreach (Server *s, qhServers) {
668 		if (s->bUsingMetaCert) {
669 			s->log("Reloading certificates...");
670 			s->initializeCert();
671 		} else {
672 			s->log("Not reloading certificates; server does not use Meta certificate");
673 		}
674 	}
675 
676 	return true;
677 }
678 
getOSInfo()679 void Meta::getOSInfo() {
680 	qsOS = OSInfo::getOS();
681 	qsOSVersion = OSInfo::getOSDisplayableVersion();
682 }
683 
bootAll()684 void Meta::bootAll() {
685 	QList<int> ql = ServerDB::getBootServers();
686 	foreach(int snum, ql)
687 		boot(snum);
688 }
689 
boot(int srvnum)690 bool Meta::boot(int srvnum) {
691 	if (qhServers.contains(srvnum))
692 		return false;
693 	if (! ServerDB::serverExists(srvnum))
694 		return false;
695 	Server *s = new Server(srvnum, this);
696 	if (! s->bValid) {
697 		delete s;
698 		return false;
699 	}
700 	qhServers.insert(srvnum, s);
701 	emit started(s);
702 
703 #ifdef Q_OS_UNIX
704 	unsigned int sockets = 19; // Base
705 	foreach(s, qhServers) {
706 		sockets += 11; // Listen sockets, signal pipes etc.
707 		sockets += s->iMaxUsers; // One per user
708 	}
709 
710 	struct rlimit r;
711 	if (getrlimit(RLIMIT_NOFILE, &r) == 0) {
712 		if (r.rlim_cur < sockets) {
713 			r.rlim_cur = sockets;
714 			if (r.rlim_max < sockets)
715 				r.rlim_max = sockets;
716 			if (setrlimit(RLIMIT_NOFILE, &r) != 0) {
717 				getrlimit(RLIMIT_NOFILE, &r);
718 				if (r.rlim_cur < r.rlim_max) {
719 					r.rlim_cur = r.rlim_max;
720 					setrlimit(RLIMIT_NOFILE, &r);
721 					getrlimit(RLIMIT_NOFILE, &r);
722 				}
723 			}
724 		}
725 		if (r.rlim_cur < sockets)
726 			qCritical("Current booted servers require minimum %d file descriptors when all slots are full, but only %lu file descriptors are allowed for this process. Your server will crash and burn; read the FAQ for details.", sockets, static_cast<unsigned long>(r.rlim_cur));
727 	}
728 #endif
729 
730 	return true;
731 }
732 
kill(int srvnum)733 void Meta::kill(int srvnum) {
734 	Server *s = qhServers.take(srvnum);
735 	if (!s)
736 		return;
737 	emit stopped(s);
738 	delete s;
739 }
740 
killAll()741 void Meta::killAll() {
742 	foreach(Server *s, qhServers) {
743 		emit stopped(s);
744 		delete s;
745 	}
746 	qhServers.clear();
747 }
748 
banCheck(const QHostAddress & addr)749 bool Meta::banCheck(const QHostAddress &addr) {
750 	if ((mp.iBanTries == 0) || (mp.iBanTimeframe == 0))
751 		return false;
752 
753 	if (qhBans.contains(addr)) {
754 		Timer t = qhBans.value(addr);
755 		if (t.elapsed() < (1000000ULL * mp.iBanTime))
756 			return true;
757 		qhBans.remove(addr);
758 	}
759 
760 	QList<Timer> &ql = qhAttempts[addr];
761 
762 	ql.append(Timer());
763 	while (! ql.isEmpty() && (ql.at(0).elapsed() > (1000000ULL * mp.iBanTimeframe)))
764 		ql.removeFirst();
765 
766 	if (ql.count() > mp.iBanTries) {
767 		qhBans.insert(addr, Timer());
768 		return true;
769 	}
770 	return false;
771 }
772