/** * @file operator-starttls.cc * @brief Implementation of the STARTTLS command - based on sslserver * @author Andreas Aardal Hanssen, Erwin Hoffmann * @date 2002-2005, 2023 */ #include "depot.h" #include "iodevice.h" #include "iofactory.h" #include "operators.h" #include "recursivedescent.h" #include "session.h" #include #include #include #include using namespace Binc; StarttlsOperator::StarttlsOperator() {} StarttlsOperator::~StarttlsOperator() {} const std::string StarttlsOperator::getName() const { return "STARTTLS"; } Session::State StarttlsOperator::getState() const { return Session::State(Session::NONAUTHENTICATED | Session::AUTHENTICATED | Session::SELECTED); } Operator::ProcessResult StarttlsOperator::goStartTLS() const { Session &session = Session::getInstance(); if (getenv("UCSPITLS")) { std::string fdstr; int fd; fdstr = session.getEnv("SSLCTLFD"); fd = std::stoi(fdstr); if (write(fd, "Y", 1) < 1) return ProcessResult::NOTHING; bincClient.flush(); // flush all previous received data fdstr = session.getEnv("SSLREADFD"); fd = std::stoi(fdstr); if (fcntl(fd, F_GETFL, 0) == -1) return ProcessResult::NOTHING; close(0); if (fcntl(fd, F_DUPFD, 0) == -1) return ProcessResult::NOTHING; close(fd); fdstr = session.getEnv("SSLWRITEFD"); fd = std::stoi(fdstr); if (fcntl(fd, F_GETFL, 0) == -1) return ProcessResult::NOTHING; close(1); if (fcntl(fd, F_DUPFD, 1) == -1) return ProcessResult::NOTHING; close(fd); } return ProcessResult::OK; } Operator::ProcessResult StarttlsOperator::process(Depot &depot, Request &command) { Session &session = Session::getInstance(); if (session.command.ssl) { session.setLastError("Already in TLS mode"); return ProcessResult::BAD; } bincClient << "* ENABLED StartTLS - begin negotiation now" << std::endl; bincClient << command.getTag() << " OK STARTTLS completed" << std::endl; if (goStartTLS() == ProcessResult::OK) session.command.ssl = true; else return ProcessResult::NO; return ProcessResult::NOTHING; } Parser::ParseResult StarttlsOperator::parse(Request &c_in, Parser &p) { Session &session = Session::getInstance(); if (c_in.getUidMode()) return Parser::ParseResult::REJECT; Parser::ParseResult res; if ((res = p.expectCRLF()) != Parser::ParseResult::ACCEPT) { session.setLastError("Expected CRLF"); return res; } c_in.setName("STARTTLS"); return Parser::ParseResult::ACCEPT; }