// Copyright 2007-2022 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #ifndef MUMBLE_MURMUR_SERVER_H_ #define MUMBLE_MURMUR_SERVER_H_ #include #ifdef Q_OS_WIN # include "win.h" #endif #include "ACL.h" #include "AudioReceiverBuffer.h" #include "Ban.h" #include "ChannelListenerManager.h" #include "HostAddress.h" #include "Mumble.pb.h" #include "MumbleProtocol.h" #include "Timer.h" #include "User.h" #include "Version.h" #ifndef Q_MOC_RUN # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(USE_QSSLDIFFIEHELLMANPARAMETERS) # include #endif #ifdef Q_OS_WIN # include #endif class Zeroconf; class Channel; class PacketDataStream; class ServerUser; class User; class QNetworkAccessManager; struct TextMessage { QList< unsigned int > qlSessions; QList< unsigned int > qlChannels; QList< unsigned int > qlTrees; QString qsText; }; class SslServer : public QTcpServer { private: Q_OBJECT; Q_DISABLE_COPY(SslServer) protected: QList< QSslSocket * > qlSockets; void incomingConnection(qintptr) Q_DECL_OVERRIDE; public: QSslSocket *nextPendingSSLConnection(); SslServer(QObject *parent = nullptr); }; #define EXEC_QEVENT (QEvent::User + 959) class ExecEvent : public QEvent { Q_DISABLE_COPY(ExecEvent); protected: boost::function< void() > func; public: ExecEvent(boost::function< void() >); void execute(); }; class Server : public QThread { private: Q_OBJECT; Q_DISABLE_COPY(Server); protected: bool bRunning; QNetworkAccessManager *qnamNetwork; #ifdef USE_ZEROCONF Zeroconf *zeroconf; #endif void startThread(); void stopThread(); void customEvent(QEvent *evt); // Former ServerParams public: QList< QHostAddress > qlBind; unsigned short usPort; int iTimeout; int iMaxBandwidth; int iMaxUsers; int iMaxUsersPerChannel; int iDefaultChan; bool bRememberChan; int iRememberChanDuration; int iMaxTextMessageLength; int iMaxImageMessageLength; int iOpusThreshold; bool bAllowHTML; QString qsPassword; QString qsWelcomeText; QString qsWelcomeTextFile; bool bCertRequired; bool bForceExternalAuth; QString qsRegName; QString qsRegPassword; QString qsRegHost; QString qsRegLocation; QUrl qurlRegWeb; bool bBonjour; bool bAllowPing; bool allowRecording; QRegExp qrUserName; QRegExp qrChannelName; unsigned int iMessageLimit; unsigned int iMessageBurst; unsigned int iPluginMessageLimit; unsigned int iPluginMessageBurst; QVariant qvSuggestVersion; QVariant qvSuggestPositional; QVariant qvSuggestPushToTalk; bool bUsingMetaCert; QSslCertificate qscCert; QSslKey qskKey; /// qlIntermediates contains the certificates /// from this virtual server's certificate PEM // bundle that do not match the virtual server's // private key. /// /// Simply put: it contains any certificates /// that aren't the main certificate, or "leaf" /// certificate. QList< QSslCertificate > qlIntermediates; #if defined(USE_QSSLDIFFIEHELLMANPARAMETERS) QSslDiffieHellmanParameters qsdhpDHParams; #endif Timer tUptime; bool bValid; ChannelListenerManager m_channelListenerManager; Mumble::Protocol::UDPDecoder< Mumble::Protocol::Role::Server > m_udpDecoder; Mumble::Protocol::UDPDecoder< Mumble::Protocol::Role::Server > m_tcpTunnelDecoder; Mumble::Protocol::UDPPingEncoder< Mumble::Protocol::Role::Server > m_udpPingEncoder; Mumble::Protocol::UDPAudioEncoder< Mumble::Protocol::Role::Server > m_udpAudioEncoder; Mumble::Protocol::UDPAudioEncoder< Mumble::Protocol::Role::Server > m_tcpAudioEncoder; gsl::span< const Mumble::Protocol::byte > handlePing(const Mumble::Protocol::UDPDecoder< Mumble::Protocol::Role::Server > &decoder, Mumble::Protocol::UDPPingEncoder< Mumble::Protocol::Role::Server > &encoder, bool expectExtended); void readParams(); int iCodecAlpha; int iCodecBeta; bool bPreferAlpha; bool bOpus; void recheckCodecVersions(ServerUser *connectingUser = 0); #ifdef USE_ZEROCONF void initZeroconf(); void removeZeroconf(); #endif // Registration, implementation in Register.cpp QTimer qtTick; void initRegister(); private: int iChannelNestingLimit; int iChannelCountLimit; AudioReceiverBuffer m_udpAudioReceivers; AudioReceiverBuffer m_tcpAudioReceivers; public slots: void regSslError(const QList< QSslError > &); void finished(); void update(); // Certificate stuff, implemented partially in Cert.cpp public: static bool isKeyForCert(const QSslKey &key, const QSslCertificate &cert); /// Attempt to load a private key in PEM format from |buf|. /// If |passphrase| is non-empty, it will be used for decrypting the private key in |buf|. /// If a valid RSA, DSA or EC key is found, it is returned. /// If no valid private key is found, a null QSslKey is returned. static QSslKey privateKeyFromPEM(const QByteArray &buf, const QByteArray &pass = QByteArray()); void initializeCert(); const QString getDigest() const; public slots: void newClient(); void connectionClosed(QAbstractSocket::SocketError, const QString &); void sslError(const QList< QSslError > &); void message(Mumble::Protocol::TCPMessageType, const QByteArray &, ServerUser *cCon = nullptr); void checkTimeout(); void tcpTransmitData(QByteArray, unsigned int); void doSync(unsigned int); void encrypted(); void udpActivated(int); signals: void reqSync(unsigned int); void tcpTransmit(QByteArray, unsigned int id); public: int iServerNum; QQueue< int > qqIds; QList< SslServer * > qlServer; QTimer *qtTimeout; #ifdef Q_OS_UNIX int aiNotify[2]; QList< int > qlUdpSocket; #else HANDLE hNotify; QList< SOCKET > qlUdpSocket; #endif Version::mumble_raw_version_t m_versionBlob; QList< QSocketNotifier * > qlUdpNotifier; /// This lock provides synchronization between the /// main thread (where control channel messages and /// RPC happens), and the Server's voice thread. /// /// These are the only two threads in Murmur that /// access a Server's data. /// /// The easiest way to understand the locking strategy /// and synchronization between the main thread and the /// Server's voice thread is by using the concept of /// ownership. /// /// A thread owning an object means that it is the only /// thread that is allowed to write to that object. To /// make changes to it. /// /// Most data in the Server class is owned by the main /// thread. That means that the main thread is the only /// thread that writes/updates those structures. /// /// When processing incoming voice data (and re- /// broadcasting) that voice data), the Server's voice /// thread needs to access various parts of Server's data, /// such as qhUsers, qhChannels, User->cChannel, etc. /// However, these are owned by the main thread. /// /// To ensure correct synchronization between the two /// threads, the contract for using qrwlVoiceThread is /// as follows: /// /// - When the Server's voice thread needs to read data /// owned by the main thread, it must hold a read lock /// on qrwlVoiceThread. /// /// - The Server's voice thread does not write to any data /// that is owned by the main thread. /// /// - When the main thread needs to write to data owned by /// itself that is accessed by the voice thread, it must /// hold a write lock on qrwlVoiceThread. /// /// - When the main thread needs to read data that is owned /// by itself, it DOES NOT hold a lock on qrwlVoiceThread. /// That is because ownership of data guarantees that no /// other thread can write to that data. QReadWriteLock qrwlVoiceThread; QHash< unsigned int, ServerUser * > qhUsers; QHash< QPair< HostAddress, quint16 >, ServerUser * > qhPeerUsers; QHash< HostAddress, QSet< ServerUser * > > qhHostUsers; QHash< unsigned int, Channel * > qhChannels; QMutex qmCache; ChanACL::ACLCache acCache; QHash< int, QString > qhUserNameCache; QHash< QString, int > qhUserIDCache; QList< Ban > qlBans; void processMsg(ServerUser *u, Mumble::Protocol::AudioData audioData, AudioReceiverBuffer &buffer, Mumble::Protocol::UDPAudioEncoder< Mumble::Protocol::Role::Server > &encoder); void sendMessage(ServerUser &u, const unsigned char *data, int len, QByteArray &cache, bool force = false); void run(); bool validateChannelName(const QString &name); bool validateUserName(const QString &name); bool checkDecrypt(ServerUser *u, const unsigned char *encrypted, unsigned char *plain, unsigned int cryptlen); bool hasPermission(ServerUser *p, Channel *c, QFlags< ChanACL::Perm > perm); QFlags< ChanACL::Perm > effectivePermissions(ServerUser *p, Channel *c); void sendClientPermission(ServerUser *u, Channel *c, bool explicitlyRequested = false); void flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mpqq); void clearACLCache(User *p = nullptr); void clearWhisperTargetCache(); void sendProtoAll(const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type, unsigned int minversion); void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type, unsigned int minversion); void sendProtoMessage(ServerUser *, const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type); // sendAll sends a protobuf message to all users on the server whose version is either bigger than v or // lower than ~v. If v == 0 the message is sent to everyone. #define PROCESS_MUMBLE_TCP_MESSAGE(name, value) \ void sendAll(const MumbleProto::name &msg, unsigned int v = 0) { \ sendProtoAll(msg, Mumble::Protocol::TCPMessageType::name, v); \ } \ void sendExcept(ServerUser *u, const MumbleProto::name &msg, unsigned int v = 0) { \ sendProtoExcept(u, msg, Mumble::Protocol::TCPMessageType::name, v); \ } \ void sendMessage(ServerUser *u, const MumbleProto::name &msg) { \ sendProtoMessage(u, msg, Mumble::Protocol::TCPMessageType::name); \ } MUMBLE_ALL_TCP_MESSAGES #undef PROCESS_MUMBLE_TCP_MESSAGE static void hashAssign(QString &destination, QByteArray &hash, const QString &str); static void hashAssign(QByteArray &destination, QByteArray &hash, const QByteArray &source); bool isTextAllowed(QString &str, bool &changed); void setLiveConf(const QString &key, const QString &value); QString addressToString(const QHostAddress &, unsigned short port); void log(const QString &) const; void log(ServerUser *u, const QString &) const; void removeChannel(int id); void removeChannel(Channel *c, Channel *dest = nullptr); void userEnterChannel(User *u, Channel *c, MumbleProto::UserState &mpus); bool unregisterUser(int id); Server(int snum, QObject *parent = nullptr); ~Server(); bool canNest(Channel *newParent, Channel *channel = nullptr) const; // RPC functions. Implementation in RPC.cpp void connectAuthenticator(QObject *p); void disconnectAuthenticator(QObject *p); void connectListener(QObject *p); void disconnectListener(QObject *p); void setTempGroups(int userid, int sessionId, Channel *cChannel, const QStringList &groups); void clearTempGroups(User *user, Channel *cChannel = nullptr, bool recurse = true); void startListeningToChannel(ServerUser *user, Channel *cChannel); void stopListeningToChannel(ServerUser *user, Channel *cChannel); void sendWelcomeMessageTo(ServerUser *user); signals: void registerUserSig(int &, const QMap< int, QString > &); void unregisterUserSig(int &, int); void getRegisteredUsersSig(const QString &, QMap< int, QString > &); void getRegistrationSig(int &, int, QMap< int, QString > &); void authenticateSig(int &, QString &, int, const QList< QSslCertificate > &, const QString &, bool, const QString &); void setInfoSig(int &, int, const QMap< int, QString > &); void setTextureSig(int &, int, const QByteArray &); void idToNameSig(QString &, int); void nameToIdSig(int &, const QString &); void idToTextureSig(QByteArray &, int); void userStateChanged(const User *); void userTextMessage(const User *, const TextMessage &); void userConnected(const User *); void userDisconnected(const User *); void channelStateChanged(const Channel *); void channelCreated(const Channel *); void channelRemoved(const Channel *); void textMessageFilterSig(int &, const User *, MumbleProto::TextMessage &); void contextAction(const User *, const QString &, unsigned int, int); public: void setUserState(User *p, Channel *parent, bool mute, bool deaf, bool suppressed, bool prioritySpeaker, const QString &name = QString(), const QString &comment = QString()); bool setChannelState(Channel *c, Channel *parent, const QString &qsName, const QSet< Channel * > &links, const QString &desc = QString(), const int position = 0); void sendTextMessage(Channel *cChannel, ServerUser *pUser, bool tree, const QString &text); /// Returns true if a channel is full. If a user is provided, false will always /// be returned if the user has write permission in the channel. bool isChannelFull(Channel *c, ServerUser *u = 0); // Database / DBus functions. Implementation in ServerDB.cpp void initialize(); int authenticate(QString &name, const QString &pw, int sessionId = 0, const QStringList &emails = QStringList(), const QString &certhash = QString(), bool bStrongCert = false, const QList< QSslCertificate > & = QList< QSslCertificate >()); Channel *addChannel(Channel *c, const QString &name, bool temporary = false, int position = 0, unsigned int maxUsers = 0); void removeChannelDB(const Channel *c); void readChannels(Channel *p = nullptr); void readLinks(); void updateChannel(const Channel *c); void readChannelPrivs(Channel *c); void setLastChannel(const User *u); int readLastChannel(int id); /// Set last_disconnect of a registered user to the current time void setLastDisconnect(const User *u); void dumpChannel(const Channel *c); int getUserID(const QString &name); QString getUserName(int id); QByteArray getUserTexture(int id); QMap< int, QString > getRegistration(int id); int registerUser(const QMap< int, QString > &info); bool unregisterUserDB(int id); QList< UserInfo > getRegisteredUsersEx(); QMap< int, QString > getRegisteredUsers(const QString &filter = QString()); bool setInfo(int id, const QMap< int, QString > &info); bool setTexture(int id, const QByteArray &texture); bool isUserId(int id); void addLink(Channel *c, Channel *l); void removeLink(Channel *c, Channel *l); void getBans(); void saveBans(); QVariant getConf(const QString &key, QVariant def); void setConf(const QString &key, const QVariant &value); void dblog(const QString &str) const; // From msgHandler. Implementation in Messages.cpp #define PROCESS_MUMBLE_TCP_MESSAGE(name, value) void msg##name(ServerUser *, MumbleProto::name &); MUMBLE_ALL_TCP_MESSAGES #undef PROCESS_MUMBLE_TCP_MESSAGE }; #endif