summaryrefslogtreecommitdiffstats
path: root/src/server/net/sslserver.cpp
blob: d968834e2b6a56fc4bb8abf804a82a4ed1172725 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
 #
 # This program is free software distributed under the GPL version 2.
 # See http://openslx.org/COPYING
 #
 # If you have any feedback please consult http://openslx.org/feedback and
 # send your suggestions, praise, or complaints to feedback@openslx.org
 #
 # General information about OpenSLX can be found at http://openslx.org/
 # -----------------------------------------------------------------------------
 # src/net/SslServer.cpp
 #    - provide QTcpServer-like behaviour for SSL
 # -----------------------------------------------------------------------------
 */

#include "sslserver.h"
#include <QtNetwork/QSslCipher>
#include <QtNetwork/QSslSocket>
#include <QTimer>
#include "certmanager.h"
#include <unistd.h>

SslServer::SslServer() : QTcpServer(nullptr), _timer(new QTimer(this))
{
	connect(_timer, &QTimer::timeout, [=]() {
		if (_pending.empty())
			return;
		const qint64 deadline = QDateTime::currentMSecsSinceEpoch() - 10000;
		QMutableHashIterator<QSslSocket*, qint64> it(_pending);
		while (it.hasNext()) { // Remove lingering connections after 10s
			it.next();
			if (it.value() < deadline) {
				it.key()->blockSignals(true);
				it.key()->deleteLater();
				it.remove();
			}
		}
	});
	_timer->start(10000);
}

SslServer::~SslServer()
{
	_timer->stop();
	for (QSslSocket *sock : _pending.keys()) {
		sock->deleteLater();
	}
}

/**
 * Handle incomming connection.
 * @param socketDescriptor
 */
void SslServer::incomingConnection(qintptr socketDescriptor)
{
	static int certFails = 0;
	QSslKey key;
	QSslCertificate cert;
	if (!CertManager::getPrivateKeyAndCert("manager", key, cert)) {
		if (++certFails > 5) {
			CertManager::fatal();
		}
		::close(int(socketDescriptor));
		return;
	}
	QSslSocket *serverSocket = new QSslSocket(nullptr);
	connect(serverSocket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &SslServer::sslErrors);
	serverSocket->setPrivateKey(key);
	serverSocket->setLocalCertificate(cert);
	serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
	serverSocket->setProtocol(QSsl::SecureProtocols);
	if (serverSocket->setSocketDescriptor(socketDescriptor)) {
		_pending.insert(serverSocket, QDateTime::currentMSecsSinceEpoch());
		// Once the connection is successfully encrypted, raise our newConnection event
		connect(serverSocket, &QSslSocket::encrypted, [=]() {
			serverSocket->disconnect(this);
			if (_pending.remove(serverSocket) == 0) {
				// Should never happen, so better log...
				qDebug() << "Encryption event for socket that is not pending!?";
			} else {
				this->addPendingConnection(serverSocket);
				emit newConnection();
			}
		});
		serverSocket->startServerEncryption();
	} else {
		qDebug() << "Failed to setSocketDescriptor on new SSL Socket";
		serverSocket->deleteLater();
	}
}

void SslServer::sslErrors(const QList<QSslError>& errors)
{
	qDebug() << "Client caused sslErrors before connection:";
	for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++) {
		qDebug() << it->errorString();
	}

}