void QwwSmtpClientPrivate::sendAuthLogin(const QString & username, const QString & password, int stage) { if (stage==1) { qDebug() << "SMTP <<< [login username]"; socket->write(username.toUtf8().toBase64()); socket->write("\r\n"); } else if (stage==2) { qDebug() << "SMTP <<< [login password]"; socket->write(password.toUtf8().toBase64()); socket->write("\r\n"); } }
void QwwSmtpClientPrivate::sendAuthPlain(const QString & username, const QString & password) { QByteArray ba; ba.append('\0'); ba.append(username.toUtf8()); ba.append('\0'); ba.append(password.toUtf8()); QByteArray encoded = ba.toBase64(); qDebug() << "SMTP <<< [authentication data]"; socket->write(encoded); socket->write("\r\n"); }
//We received a UDP package and answered by connecting to them by TCP. This gets called on a succesful connection. void LanLinkProvider::connected() { qCDebug(KDECONNECT_CORE) << "Socket connected"; QSslSocket* socket = qobject_cast<QSslSocket*>(sender()); if (!socket) return; disconnect(socket, &QAbstractSocket::connected, this, &LanLinkProvider::connected); disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); configureSocket(socket); // If socket disconnects due to any reason after connection, link on ssl faliure connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); NetworkPackage* receivedPackage = receivedIdentityPackages[socket].np; const QString& deviceId = receivedPackage->get<QString>(QStringLiteral("deviceId")); //qCDebug(KDECONNECT_CORE) << "Connected" << socket->isWritable(); // If network is on ssl, do not believe when they are connected, believe when handshake is completed NetworkPackage np2(QLatin1String("")); NetworkPackage::createIdentityPackage(&np2); socket->write(np2.serialize()); bool success = socket->waitForBytesWritten(); if (success) { qCDebug(KDECONNECT_CORE) << "TCP connection done (i'm the existing device)"; // if ssl supported if (receivedPackage->get<int>(QStringLiteral("protocolVersion")) >= MIN_VERSION_WITH_SSL_SUPPORT) { bool isDeviceTrusted = KdeConnectConfig::instance()->trustedDevices().contains(deviceId); configureSslSocket(socket, deviceId, isDeviceTrusted); qCDebug(KDECONNECT_CORE) << "Starting server ssl (I'm the client TCP socket)"; connect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted); if (isDeviceTrusted) { connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); } socket->startServerEncryption(); return; // Return statement prevents from deleting received package, needed in slot "encrypted" } else { qWarning() << receivedPackage->get<QString>(QStringLiteral("deviceName")) << "uses an old protocol version, this won't work"; //addLink(deviceId, socket, receivedPackage, LanDeviceLink::Remotely); } } else { //I think this will never happen, but if it happens the deviceLink //(or the socket that is now inside it) might not be valid. Delete them. qCDebug(KDECONNECT_CORE) << "Fallback (2), try reverse connection (send udp packet)"; mUdpSocket.writeDatagram(np2.serialize(), receivedIdentityPackages[socket].sender, PORT); } delete receivedIdentityPackages.take(socket).np; //We don't delete the socket because now it's owned by the LanDeviceLink }
void QwwSmtpClientPrivate::sendQuit() { qDebug() << "SMTP >>> QUIT"; socket->write("QUIT\r\n"); socket->waitForBytesWritten(1000); socket->disconnectFromHost(); setState(QwwSmtpClient::Disconnecting); }
void QwwSmtpClientPrivate::sendHelo() { SMTPCommand &cmd = commandqueue.head(); QString domain = localName; if (socket->isEncrypted() && localNameEncrypted.isEmpty()) domain = localNameEncrypted; QByteArray buf = QString("HELO "+domain+"\r\n").toUtf8(); qDebug() << "SMTP >>>" << buf; socket->write(buf); cmd.extra = 1; }
void QwwSmtpClientPrivate::sendRcpt() { SMTPCommand &cmd = commandqueue.head(); QVariantList vlist = cmd.data.toList(); QList<QVariant> rcptlist = vlist.at(1).toList(); QByteArray buf = QByteArray("RCPT TO:<").append(rcptlist.first().toByteArray()).append(">\r\n"); qDebug() << "SMTP >>>" << buf; socket->write(buf); rcptlist.removeFirst(); vlist[1] = rcptlist; cmd.data = vlist; if (rcptlist.isEmpty()) cmd.extra = 1; }
void Server::sendFortune() { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_0); qDebug() << "In sendFortune"; out << (quint16)0; out << fortunes.at(qrand() % fortunes.size()); out.device()->seek(0); out << (quint16)(block.size() - sizeof(quint16)); QSslSocket *clientConnection = sslServer->nextPendingConnection(); if (!clientConnection->waitForEncrypted(1000)){ qDebug() << "Waited for 1 second for encryption handshake without success"; return; } qDebug() << "Successfully waited for secure handshake..."; connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater())); clientConnection->write(block); clientConnection->disconnectFromHost(); }
void QwwSmtpClientPrivate::processNextCommand(bool ok) { if (inProgress && !commandqueue.isEmpty()) { emit q->commandFinished(commandqueue.head().id, !ok); commandqueue.dequeue(); } if (commandqueue.isEmpty()) { inProgress = false; emit q->done(false); return; } const SMTPCommand &cmd = commandqueue.head(); switch (cmd.type) { case SMTPCommand::Connect: { QString hostName = cmd.data.toList().at(0).toString(); uint port = cmd.data.toList().at(1).toUInt(); bool ssl = cmd.data.toList().at(2).toBool(); if(ssl){ qDebug() << "SMTP ** connectToHostEncrypted"; socket->connectToHostEncrypted(hostName, port); } else { qDebug() << "SMTP ** connectToHost"; socket->connectToHost(hostName, port); } setState(QwwSmtpClient::Connecting); } break; case SMTPCommand::Disconnect: { sendQuit(); } break; case SMTPCommand::StartTLS: { qDebug() << "SMTP >>> STARTTLS"; socket->write("STARTTLS\r\n"); setState(QwwSmtpClient::TLSRequested); } break; case SMTPCommand::Authenticate: { QwwSmtpClient::AuthMode authmode = (QwwSmtpClient::AuthMode)cmd.data.toList().at(0).toInt(); switch (authmode) { case QwwSmtpClient::AuthPlain: qDebug() << "SMTP >>> AUTH PLAIN"; socket->write("AUTH PLAIN\r\n"); setState(QwwSmtpClient::Authenticating); break; case QwwSmtpClient::AuthLogin: qDebug() << "SMTP >>> AUTH LOGIN"; socket->write("AUTH LOGIN\r\n"); setState(QwwSmtpClient::Authenticating); break; default: qWarning("Unsupported or unknown authentication scheme"); //processNextCommand(false); } } break; case SMTPCommand::Mail: case SMTPCommand::MailBurl: { setState(QwwSmtpClient::Sending); QByteArray buf = QByteArray("MAIL FROM:<").append(cmd.data.toList().at(0).toByteArray()).append(">\r\n"); qDebug() << "SMTP >>>" << buf; socket->write(buf); break; } case SMTPCommand::RawCommand: { QString cont = cmd.data.toString(); if(!cont.endsWith("\r\n")) cont.append("\r\n"); setState(QwwSmtpClient::Sending); qDebug() << "SMTP >>>" << cont; socket->write(cont.toUtf8()); } break; } inProgress = true; emit q->commandStarted(cmd.id); }
// main logic of the component - a slot triggered upon data entering the socket // comments inline... void QwwSmtpClientPrivate::_q_readFromSocket() { while (socket->canReadLine()) { QString line = socket->readLine(); qDebug() << "SMTP <<<" << line.toUtf8().constData(); QRegExp rx("(\\d+)-(.*)\n"); // multiline response (aka 250-XYZ) QRegExp rxlast("(\\d+) (.*)\n"); // single or last line response (aka 250 XYZ) bool mid = rx.exactMatch(line); bool last = rxlast.exactMatch(line); // multiline if (mid){ int status = rx.cap(1).toInt(); SMTPCommand &cmd = commandqueue.head(); switch (cmd.type) { // trying to connect case SMTPCommand::Connect: { int stage = cmd.extra.toInt(); // stage 0 completed with success - socket is connected and EHLO was sent if(stage==1 && status==250){ QString arg = rx.cap(2).trimmed(); parseOption(arg); // we're probably receiving options } } break; // trying to establish deferred SSL handshake case SMTPCommand::StartTLS: { int stage = cmd.extra.toInt(); // stage 0 (negotiation) completed ok if(stage==1 && status==250){ QString arg = rx.cap(2).trimmed(); parseOption(arg); // we're probably receiving options } } default: break; } } else // single line if (last) { int status = rxlast.cap(1).toInt(); SMTPCommand &cmd = commandqueue.head(); switch (cmd.type) { // trying to connect case SMTPCommand::Connect: { int stage = cmd.extra.toInt(); // connection established, server sent its banner if (stage==0 && status==220) { sendEhlo(); // connect ok, send ehlo } // server responded to EHLO if (stage==1 && status==250){ // success (EHLO) parseOption(rxlast.cap(2).trimmed()); // we're probably receiving the last option errorString.clear(); setState(QwwSmtpClient::Connected); processNextCommand(); } // server responded to HELO (EHLO failed) if (state==2 && status==250) { // success (HELO) errorString.clear(); setState(QwwSmtpClient::Connected); processNextCommand(); } // EHLO failed, reason given in errorString if (stage==1 && (status==554 || status==501 || status==502 || status==421)) { errorString = rxlast.cap(2).trimmed(); sendHelo(); // ehlo failed, send helo cmd.extra = 2; } //abortDialog(); } break; // trying to establish a delayed SSL handshake case SMTPCommand::StartTLS: { int stage = cmd.extra.toInt(); // received an invitation from the server to enter TLS mode if (stage==0 && status==220) { qDebug() << "SMTP ** startClientEncruption"; socket->startClientEncryption(); } // TLS established, connection is encrypted, EHLO was sent else if (stage==1 && status==250) { setState(QwwSmtpClient::Connected); parseOption(rxlast.cap(2).trimmed()); // we're probably receiving options errorString.clear(); emit q->tlsStarted(); processNextCommand(); } // starttls failed else { qDebug() << "TLS failed at stage " << stage << ": " << line; errorString = "TLS failed"; emit q->done(false); } } break; // trying to authenticate the client to the server case SMTPCommand::Authenticate: { int stage = cmd.extra.toInt(); if (stage==0 && status==334) { // AUTH mode was accepted by the server, 1st challenge sent QwwSmtpClient::AuthMode authmode = (QwwSmtpClient::AuthMode)cmd.data.toList().at(0).toInt(); errorString.clear(); switch (authmode) { case QwwSmtpClient::AuthPlain: sendAuthPlain(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString()); break; case QwwSmtpClient::AuthLogin: sendAuthLogin(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString(), 1); break; default: qWarning("I shouldn't be here"); setState(QwwSmtpClient::Connected); processNextCommand(); break; } cmd.extra = stage+1; } else if (stage==1 && status==334) { // AUTH mode and user names were acccepted by the server, 2nd challenge sent QwwSmtpClient::AuthMode authmode = (QwwSmtpClient::AuthMode)cmd.data.toList().at(0).toInt(); errorString.clear(); switch (authmode) { case QwwSmtpClient::AuthPlain: // auth failed setState(QwwSmtpClient::Connected); processNextCommand(); break; case QwwSmtpClient::AuthLogin: sendAuthLogin(cmd.data.toList().at(1).toString(), cmd.data.toList().at(2).toString(), 2); break; default: qWarning("I shouldn't be here"); setState(QwwSmtpClient::Connected); processNextCommand(); break; } } else if (stage==2 && status==334) { // auth failed errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); processNextCommand(); } else if (status==235) { // auth ok errorString.clear(); emit q->authenticated(); setState(QwwSmtpClient::Connected); processNextCommand(); } else { errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); emit q->done(false); } } break; // trying to send mail case SMTPCommand::Mail: case SMTPCommand::MailBurl: { int stage = cmd.extra.toInt(); // temporary failure upon receiving the sender address (greylisting probably) if (status==421 && stage==0) { errorString = rxlast.cap(2).trimmed(); // temporary envelope failure (greylisting) setState(QwwSmtpClient::Connected); processNextCommand(false); } if (status==250 && stage==0) { // sender accepted errorString.clear(); sendRcpt(); } else if (status==250 && stage==1) { // all receivers accepted if (cmd.type == SMTPCommand::MailBurl) { errorString.clear(); QByteArray url = cmd.data.toList().at(2).toByteArray(); qDebug() << "SMTP >>> BURL" << url << "LAST"; socket->write("BURL " + url + " LAST\r\n"); cmd.extra=2; } else { errorString.clear(); qDebug() << "SMTP >>> DATA"; socket->write("DATA\r\n"); cmd.extra=2; } } else if ((cmd.type == SMTPCommand::Mail && status==354 && stage==2)) { // DATA command accepted errorString.clear(); QByteArray toBeWritten = cmd.data.toList().at(2).toString().toUtf8(); qDebug() << "SMTP >>>" << toBeWritten << "\r\n.\r\n"; socket->write(toBeWritten); // expecting data to be already escaped (CRLF.CRLF) socket->write("\r\n.\r\n"); // termination token - CRLF.CRLF cmd.extra=3; } else if ((cmd.type == SMTPCommand::MailBurl && status==354 && stage==2)) { // BURL succeeded setState(QwwSmtpClient::Connected); errorString.clear(); processNextCommand(); } else if ((cmd.type == SMTPCommand::Mail && status==250 && stage==3)) { // mail queued setState(QwwSmtpClient::Connected); errorString.clear(); processNextCommand(); } else { // something went wrong errorString = rxlast.cap(2).trimmed(); setState(QwwSmtpClient::Connected); emit q->done(false); processNextCommand(); } } default: break; } } else { qDebug() << "None of two regular expressions matched the input" << line; } } }
void LanLinkProvider::connected() { qCDebug(KDECONNECT_CORE) << "Socket connected"; QSslSocket* socket = qobject_cast<QSslSocket*>(sender()); if (!socket) return; disconnect(socket, SIGNAL(connected()), this, SLOT(connected())); disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); configureSocket(socket); // If socket disconnects due to any reason after connection, link on ssl faliure connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); NetworkPackage* receivedPackage = receivedIdentityPackages[socket].np; const QString& deviceId = receivedPackage->get<QString>("deviceId"); //qCDebug(KDECONNECT_CORE) << "Connected" << socket->isWritable(); // If network is on ssl, do not believe when they are connected, believe when handshake is completed NetworkPackage np2(""); NetworkPackage::createIdentityPackage(&np2); socket->write(np2.serialize()); bool success = socket->waitForBytesWritten(); if (success) { qCDebug(KDECONNECT_CORE) << "Handshaking done (i'm the existing device)"; // if ssl supported if (receivedPackage->get<int>("protocolVersion") >= NetworkPackage::ProtocolVersion) { // since I support ssl and remote device support ssl socket->setPeerVerifyName(deviceId); QString certString = KdeConnectConfig::instance()->getDeviceProperty(deviceId, "certificate", QString()); if (!certString.isEmpty()) { qCDebug(KDECONNECT_CORE) << "Device trusted"; socket->addCaCertificate(QSslCertificate(certString.toLatin1())); socket->setPeerVerifyMode(QSslSocket::VerifyPeer); connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); } else { qCDebug(KDECONNECT_CORE) << "Device untrusted"; // Do not care about ssl errors here, socket will not be closed due to errors because of query peer socket->setPeerVerifyMode(QSslSocket::QueryPeer); connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrorsLogButIgnore(QList<QSslError>))); } qCDebug(KDECONNECT_CORE) << "Starting server ssl (I'm the client TCP socket)"; connect(socket, SIGNAL(encrypted()), this, SLOT(encrypted())); socket->startServerEncryption(); return; // Return statement prevents from deleting received package, needed in slot "encrypted" } else { qWarning() << "Incompatible protocol version, this won't work"; //addLink(deviceId, socket, receivedPackage, LanDeviceLink::Remotely); } } else { //I think this will never happen, but if it happens the deviceLink //(or the socket that is now inside it) might not be valid. Delete them. qCDebug(KDECONNECT_CORE) << "Fallback (2), try reverse connection (send udp packet)"; mUdpSocket.writeDatagram(np2.serialize(), receivedIdentityPackages[socket].sender, port); } delete receivedIdentityPackages.take(socket).np; //We don't delete the socket because now it's owned by the LanDeviceLink }
bool ssh::dossh() { #ifdef USE_QSSH { if(m_connection && m_connection->state() != QSsh::SshConnection::Unconnected) { helpers::log("ssh: already connecting...", LOG_INF, qApp, 0); return true; } m_connection = new QSsh::SshConnection(params, this); connect(m_connection, SIGNAL(connected()), SLOT(onQsshConnected())); connect(m_connection, SIGNAL(error(QSsh::SshError)), SLOT(onQsshConnectionError(QSsh::SshError))); helpers::log("ssh: connecting START...", LOG_INF, qApp, 0); m_connection->connectToHost(); return false; } #else helpers::log("ssh: START: " + QString::number(QSslSocket::supportsSsl()), QSslSocket::supportsSsl() ? LOG_INF : LOG_ERR, qApp, 0); //http://stackoverflow.com/questions/15213139/simple-qssl-client-server-cannot-start-handshake-on-non-plain-connection QSslSocket *socket = new QSslSocket(this); socket->ignoreSslErrors(); socket->setPeerVerifyMode(QSslSocket::VerifyNone); socket->setProtocol(QSsl::SslV3); connect(socket, SIGNAL(encrypted()), this, SLOT(ready())); connect(socket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(encryptedBytesWritten(qint64))); connect(socket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(modeChanged(QSslSocket::SslMode))); connect(socket, SIGNAL(peerVerifyError(const QSslError &)), this, SLOT(peerVerifyError(const QSslError &))); connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &))); connect(socket, SIGNAL(connected()), this, SLOT(connected())); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); connect(socket, SIGNAL(hostFound()), this, SLOT(hostFound())); connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), this, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *))); connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(stateChanged(QAbstractSocket::SocketState))); connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); { { QFile file( "c:/Users/gherczeg/.ssh/id_boot2docker" ); if( ! file.open( QIODevice::ReadOnly ) ) { QMessageBox::question(0, "Erreur", "Impossible de charger id_boot2docker"); return; } QSslKey key(&file); file.close(); helpers::log("ssh:keyok: "+QString::number(!key.isNull()), !key.isNull() ? LOG_INF : LOG_ERR, qApp, 0); socket->setPrivateKey( key ); } foreach (const QSslCertificate &cert, QSslCertificate::fromPath("c:/Users/gherczeg/.boot2docker/certs/boot2docker-vm/*.pem", QSsl::Pem, QRegExp::Wildcard)) { helpers::log("ssh:certok1: "+QString::number(!cert.isNull()), !cert.isNull() ? LOG_INF : LOG_ERR, qApp, 0); socket->setLocalCertificate( cert ); socket->sslConfiguration().caCertificates().append(cert); socket->addCaCertificate( cert ); socket->addDefaultCaCertificate(cert); } } socket->connectToHostEncrypted("127.0.0.1", 2022); //socket->connectToHost("127.0.0.1", 2022); bool bok = socket->waitForEncrypted(100000); //bool bok = socket->waitForConnected(100000); if(!bok) { helpers::log("ssh:!waited:"+QString::number(bok),LOG_ERR, qApp, 0); return; } helpers::log("ssh:waited4ecnrypt/connect:"+QString::number(bok),LOG_INF, qApp, 0); socket->startClientEncryption(); bool wait4Read1 = socket->waitForReadyRead(100000); helpers::log("ssh:wait4Read1:"+QString::number(wait4Read1),wait4Read1 ? LOG_INF : LOG_ERR, qApp, 0); QString s = "docker: do!"; qint64 written = socket->write(s.toStdString().c_str()); helpers::log("ssh:written:"+QString::number(written),written > 0 ? LOG_INF : LOG_ERR, qApp, 0); bool flushed = socket->flush(); helpers::log("ssh:flush:"+QString::number(flushed),flushed ? LOG_INF : LOG_ERR, qApp, 0); bool wait4Write = socket->waitForBytesWritten(100000); helpers::log("ssh:wait4Write:"+QString::number(wait4Write),wait4Write ? LOG_INF : LOG_ERR, qApp, 0); bool wait4Read2 = socket->waitForReadyRead(100000); helpers::log("ssh:wait4Read2:"+QString::number(wait4Read2),wait4Read2 ? LOG_INF : LOG_ERR, qApp, 0); socket->disconnectFromHost(); #endif }