Exemple #1
0
static JSON::Value parse(yaml_parser_t &parser)
{
    JSON::Value result;
    yaml_document_t document;
    if (!yaml_parser_load(&parser, &document)) {
        yaml_error_type_t error = parser.error;
        MORDOR_ASSERT(error != YAML_NO_ERROR);
        Exception exception(parser.problem, parser.context);
        yaml_parser_delete(&parser);
        switch (error) {
            case YAML_MEMORY_ERROR:
                MORDOR_THROW_EXCEPTION(std::bad_alloc());
            case YAML_READER_ERROR:
                MORDOR_THROW_EXCEPTION(InvalidUnicodeException());
            default:
                MORDOR_THROW_EXCEPTION(exception);
        }
    }

    try {
        convertNode(result, yaml_document_get_root_node(&document), document);
        yaml_document_delete(&document);
        yaml_parser_delete(&parser);
        return result;
    } catch (...) {
        yaml_document_delete(&document);
        yaml_parser_delete(&parser);
        throw;
    }
}
Exemple #2
0
size_t
SSLStream::read(void *buffer, size_t length)
{
    const int toRead = (int)std::min<size_t>(0x0fffffff, length);
    while (true) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_read, m_ssl.get(), buffer, toRead), &error);
        if (result > 0) {
            return result;
        }
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_read(" << m_ssl.get() << ", "
            << toRead << "): " << result << " (" << error << ")";
        switch (error) {
            case SSL_ERROR_NONE:
                return result;
            case SSL_ERROR_ZERO_RETURN:
                // Received close_notify message
                MORDOR_ASSERT(result == 0);
                return 0;
            case SSL_ERROR_WANT_READ:
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_read("
                        << m_ssl.get() << ", " << toRead << "): " << result
                        << " (" << error << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_read");
                    ;
                }
                MORDOR_LOG_WARNING(g_log) << this << " SSL_read("
                    << m_ssl.get() << ", " << toRead << "): " << result
                    << " (" << error << ")";
                if (result == 0) {
                    return 0;
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_read");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_read("
                        << m_ssl.get() << ", " << toRead << "): " << result
                        << " (" << error << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_read");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Exemple #3
0
ptrdiff_t
BufferedStream::find(const std::string &str, size_t sanitySize, bool throwIfNotFound)
{
    if (supportsSeek())
        flush(false);
    if (sanitySize == (size_t)~0)
        sanitySize = 2 * m_bufferSize;
    sanitySize += str.size();
    while (true) {
        size_t readAvailable = m_readBuffer.readAvailable();
        if (readAvailable > 0) {
            ptrdiff_t result = m_readBuffer.find(str, std::min(sanitySize, readAvailable));
            if (result != -1) {
                return result;
            }
        }
        if (readAvailable >= sanitySize) {
            if (throwIfNotFound)
                MORDOR_THROW_EXCEPTION(BufferOverflowException());
            return -(ptrdiff_t)m_readBuffer.readAvailable() - 1;
        }

        MORDOR_LOG_TRACE(g_log) << this << " parent()->read(" << m_bufferSize
            << ")";
        size_t result = parent()->read(m_readBuffer, m_bufferSize);
        MORDOR_LOG_DEBUG(g_log) << this << " parent()->read(" << m_bufferSize
            << "): " << result;
        if (result == 0) {
            // EOF
            if (throwIfNotFound)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            return -(ptrdiff_t)m_readBuffer.readAvailable() - 1;
        }
    }
}
Exemple #4
0
BodyPart::BodyPart(Multipart::ptr multipart)
: m_multipart(multipart)
{
    if (m_multipart->m_stream->supportsRead()) {
        HTTP::TrailerParser parser(m_headers);
        parser.run(m_multipart->m_stream);
        if (parser.error())
            MORDOR_THROW_EXCEPTION(HTTP::BadMessageHeaderException());
        if (!parser.complete())
            MORDOR_THROW_EXCEPTION(HTTP::IncompleteMessageHeaderException());
        m_stream.reset(new BodyPartStream(m_multipart->m_stream, m_multipart->m_boundary));
        NotifyStream *notify = new NotifyStream(m_stream);
        notify->notifyOnEof = boost::bind(&Multipart::partDone, m_multipart);
        m_stream.reset(notify);
    }
}
Exemple #5
0
Multipart::Multipart(Stream::ptr stream, std::string boundary)
: m_stream(stream),
  m_boundary(boundary),
  m_finished(false)
{
    MORDOR_ASSERT(m_stream);
    MORDOR_ASSERT(m_stream->supportsRead() || m_stream->supportsWrite());
    MORDOR_ASSERT(!(m_stream->supportsRead() && m_stream->supportsWrite()));
    while (!m_boundary.empty() && m_boundary[m_boundary.size() - 1] == ' ')
        m_boundary.resize(m_boundary.size() - 1);
    MORDOR_ASSERT(!m_boundary.empty());
    MORDOR_ASSERT(m_boundary.size() <= 70);
    if (m_boundary.find_first_not_of(allowedBoundaryChars) != std::string::npos) {
        if (stream->supportsWrite()) {
            MORDOR_ASSERT(false);
        } else {
            MORDOR_THROW_EXCEPTION(InvalidMultipartBoundaryException());
        }
    }
    m_boundary = "\r\n--" + m_boundary;
    if (m_stream->supportsRead()) {
        MORDOR_ASSERT(m_stream->supportsFind());
        MORDOR_ASSERT(m_stream->supportsUnread());
    }
}
Exemple #6
0
SSLStream::SSLStream(Stream::ptr parent, bool client, bool own, SSL_CTX *ctx)
: MutatingFilterStream(parent, own)
{
    MORDOR_ASSERT(parent);
    clearSSLError();
    if (ctx)
        m_ctx.reset(ctx, &nop<SSL_CTX *>);
    else
        m_ctx.reset(SSL_CTX_new(client ? SSLv23_client_method() :
            SSLv23_server_method()), &SSL_CTX_free);
    if (!m_ctx) {
        MORDOR_ASSERT(hasOpenSSLError());
        MORDOR_THROW_EXCEPTION(OpenSSLException(getOpenSSLErrorMessage()))
           // << boost::errinfo_api_function("SSL_CTX_new");
        ;
    }
    // Auto-generate self-signed server cert
    if (!ctx && !client) {
        std::shared_ptr<X509> cert;
        std::shared_ptr<EVP_PKEY> pkey;
        mkcert(cert, pkey, 1024, rand(), 365);
        SSL_CTX_use_certificate(m_ctx.get(), cert.get());
        SSL_CTX_use_PrivateKey(m_ctx.get(), pkey.get());
    }
    m_ssl.reset(SSL_new(m_ctx.get()), &SSL_free);
    if (!m_ssl) {
        MORDOR_ASSERT(hasOpenSSLError());
        MORDOR_THROW_EXCEPTION(OpenSSLException(getOpenSSLErrorMessage()))
          //  << boost::errinfo_api_function("SSL_CTX_new");
        ;
    }
    m_readBio = BIO_new(BIO_s_mem());
    m_writeBio = BIO_new(BIO_s_mem());
    if (!m_readBio || !m_writeBio) {
        if (m_readBio) BIO_free(m_readBio);
        if (m_writeBio) BIO_free(m_writeBio);
        MORDOR_ASSERT(hasOpenSSLError());
        MORDOR_THROW_EXCEPTION(OpenSSLException(getOpenSSLErrorMessage()))
          //  << boost::errinfo_api_function("BIO_new");
        ;
    }
    BIO_set_mem_eof_return(m_readBio, -1);

    SSL_set_bio(m_ssl.get(), m_readBio, m_writeBio);
}
Exemple #7
0
JSON::Value parse(const std::string &string)
{
    yaml_parser_t parser;
    if (!yaml_parser_initialize(&parser))
        MORDOR_THROW_EXCEPTION(std::bad_alloc());
    yaml_parser_set_input_string(&parser,
        (const unsigned char *)string.c_str(), string.size());
    return parse(parser);
}
Exemple #8
0
void
Buffer::copyIn(const Buffer &buffer, size_t length, size_t pos)
{
    if (pos > buffer.readAvailable())
        MORDOR_THROW_EXCEPTION(std::out_of_range("position out of range"));

    if (length == (size_t)~0)
        length = buffer.readAvailable() - pos;
    MORDOR_ASSERT(buffer.readAvailable() >= length + pos);
    invariant();
    if (length == 0)
        return;

    // Split any mixed read/write bufs
    if (m_writeIt != m_segments.end() && m_writeIt->readAvailable() != 0) {
        m_segments.insert(m_writeIt, Segment(m_writeIt->readBuffer()));
        m_writeIt->consume(m_writeIt->readAvailable());
        invariant();
    }

    std::list<Segment>::const_iterator it = buffer.m_segments.begin();
    while (pos != 0 && it != buffer.m_segments.end()) {
        if (pos < it->readAvailable())
            break;
        pos -= it->readAvailable();
        ++it;
    }
    MORDOR_ASSERT(it != buffer.m_segments.end());
    for (; it != buffer.m_segments.end(); ++it) {
        size_t toConsume = (std::min)(it->readAvailable() - pos, length);
        if (m_readAvailable != 0 && it == buffer.m_segments.begin()) {
            std::list<Segment>::iterator previousIt = m_writeIt;
            --previousIt;
            if ((char *)previousIt->readBuffer().start() +
                previousIt->readBuffer().length() == (char *)it->readBuffer().start() + pos &&
                previousIt->m_data.m_array.get() == it->m_data.m_array.get()) {
                MORDOR_ASSERT(previousIt->writeAvailable() == 0);
                previousIt->extend(toConsume);
                m_readAvailable += toConsume;
                length -= toConsume;
                pos = 0;
                if (length == 0)
                    break;
                continue;
            }
        }
        Segment newSegment = Segment(it->readBuffer().slice(pos, toConsume));
        m_segments.insert(m_writeIt, newSegment);
        m_readAvailable += toConsume;
        length -= toConsume;
        pos = 0;
        if (length == 0)
            break;
    }
    MORDOR_ASSERT(length == 0);
    MORDOR_ASSERT(readAvailable() >= length);
}
Exemple #9
0
long long
HandleStream::seek(long long offset, Anchor anchor)
{
    SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
    if (m_ioManager) {
        if (supportsSeek()) {
            switch (anchor) {
                case BEGIN:
                    if (offset < 0) {
                        MORDOR_THROW_EXCEPTION(std::invalid_argument("resulting offset is negative"));
                    }
                    return m_pos = offset;
                case CURRENT:
                    if (m_pos + offset < 0) {
                        MORDOR_THROW_EXCEPTION(std::invalid_argument("resulting offset is negative"));
                    }
                    return m_pos += offset;
                case END:
                    {
                        long long end = size();
                        if (end + offset < 0) {
                            MORDOR_THROW_EXCEPTION(std::invalid_argument("resulting offset is negative"));
                        }
                        return m_pos = end + offset;
                    }
                default:
                    MORDOR_ASSERT(false);
            }
        } else {
            MORDOR_ASSERT(false);
        }
    }

    long long pos;
    BOOL ret = SetFilePointerEx(m_hFile, *(LARGE_INTEGER*)&offset,
        (LARGE_INTEGER*)&pos, (DWORD)anchor);
    DWORD error = GetLastError();
    MORDOR_LOG_LEVEL(g_log, ret ? Log::VERBOSE : Log::ERROR) << this
        << " SetFilePointerEx(" << m_hFile << ", " << offset << ", " << pos
        << ", " << anchor << "): " << ret << " (" << error << ")";
    if (!ret)
        MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "SetFilePointerEx");
    return pos;
}
Exemple #10
0
void
SSLStream::verifyPeerCertificate()
{
    const long verifyResult = sslCallWithLock(std::bind(SSL_get_verify_result, m_ssl.get()), NULL);
    MORDOR_LOG_LEVEL(g_log, verifyResult ? Log::WARNING : Log::DBG) << this
        << " SSL_get_verify_result(" << m_ssl.get() << "): "
        << verifyResult;
    if (verifyResult != X509_V_OK)
        MORDOR_THROW_EXCEPTION(CertificateVerificationException(verifyResult));
}
Exemple #11
0
size_t
HandleStream::write(const void *buffer, size_t length)
{
    if (m_cancelWrite)
        MORDOR_THROW_EXCEPTION(OperationAbortedException());
    SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
    DWORD written;
    OVERLAPPED *overlapped = NULL;
    if (m_ioManager) {
        MORDOR_ASSERT(Scheduler::getThis());
        m_ioManager->registerEvent(&m_writeEvent);
        overlapped = &m_writeEvent.overlapped;
        if (supportsSeek()) {
            overlapped->Offset = (DWORD)m_pos;
            overlapped->OffsetHigh = (DWORD)(m_pos >> 32);
        }
    }
    length = (std::min)(length, m_maxOpSize);
    BOOL ret = WriteFile(m_hFile, buffer, (DWORD)length, &written, overlapped);
    Log::Level level = Log::DEBUG;
    if (!ret) {
        if (m_ioManager && GetLastError() == ERROR_IO_PENDING)
            level = Log::TRACE;
        else
            level = Log::ERROR;
    }
    DWORD error = GetLastError();
    MORDOR_LOG_LEVEL(g_log, level) << this << " WriteFile(" << m_hFile << ", "
        << length << "): " << ret << " - " << written << " (" << error << ")";
    if (m_ioManager) {
        if (!ret && error != ERROR_IO_PENDING) {
            m_ioManager->unregisterEvent(&m_writeEvent);
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("WriteFile");
        }
        if (m_skipCompletionPortOnSuccess && ret)
            m_ioManager->unregisterEvent(&m_writeEvent);
        else
            Scheduler::yieldTo();
        DWORD error = pRtlNtStatusToDosError((NTSTATUS)m_writeEvent.overlapped.Internal);
        MORDOR_LOG_LEVEL(g_log, error ? Log::ERROR : Log::VERBOSE) << this
            << " WriteFile(" << m_hFile << ", " << length << "): "
            << m_writeEvent.overlapped.InternalHigh << " (" << error << ")";
        if (error)
            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile");
        if (supportsSeek()) {
            m_pos = ((long long)overlapped->Offset | ((long long)overlapped->OffsetHigh << 32)) +
                m_writeEvent.overlapped.InternalHigh;
        }
        return m_writeEvent.overlapped.InternalHigh;
    }
    if (!ret)
        MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile");
    return written;
}
Exemple #12
0
BodyPart::ptr
Multipart::nextPart()
{
    if (m_stream->supportsWrite()) {
        MORDOR_ASSERT(!m_finished);
        MORDOR_ASSERT(!m_currentPart);
        m_currentPart.reset(new BodyPart(shared_from_this()));
        std::string boundary = m_boundary + "\r\n";
        m_stream->write(boundary.c_str(), boundary.size());
        return m_currentPart;
    } else {
        if (m_finished) {
            MORDOR_ASSERT(!m_currentPart);
            return m_currentPart;
        }
        if (m_currentPart) {
            transferStream(m_currentPart->stream(), NullStream::get());
            // Changed by the notification callback
            MORDOR_ASSERT(!m_currentPart);
        }
        size_t offsetToBoundary = m_stream->find(m_boundary);

        Buffer b;
        size_t result = m_stream->read(b, offsetToBoundary + m_boundary.size());
        MORDOR_ASSERT(result == offsetToBoundary + m_boundary.size());
        b.clear();
        result = m_stream->read(b, 2);
        if (b == "--") {
            m_finished = true;
        }
        if (b == "\n") {
            m_stream->unread(b, 1);
        }
        if (b != "\r\n") {
            std::string restOfLine = m_stream->getDelimited();
            MORDOR_ASSERT(!restOfLine.empty());
            restOfLine.resize(restOfLine.size() - 1);
            if (restOfLine.find_first_not_of(" \r\t") != std::string::npos) {
                MORDOR_THROW_EXCEPTION(InvalidMultipartBoundaryException());
            }
        }

        if (m_finished) {
            if (multipartFinished)
                multipartFinished();
            return m_currentPart;
        }
        m_currentPart.reset(new BodyPart(shared_from_this()));
        return m_currentPart;
    }
}
Exemple #13
0
JSON::Value parse(Stream &stream)
{
    yaml_parser_t parser;
    if (!yaml_parser_initialize(&parser))
        MORDOR_THROW_EXCEPTION(std::bad_alloc());
    GetDataContext context;
    context.stream = &stream;
    yaml_parser_set_input(&parser, &getData, &context);
    try {
        return parse(parser);
    } catch (...) {
        if (context.exception)
            ::Mordor::rethrow_exception(context.exception);
        throw;
    }
}
Exemple #14
0
static void convertNode(JSON::Value &value, yaml_node_t *node,
    yaml_document_t &document)
{
    switch (node->type) {
        case YAML_SCALAR_NODE:
            value = std::string((char *)node->data.scalar.value,
                node->data.scalar.length);
            break;
        case YAML_SEQUENCE_NODE:
        {
            value = JSON::Array();
            JSON::Array &array = value.get<JSON::Array>();
            yaml_node_item_t *item = node->data.sequence.items.start;
            array.resize(node->data.sequence.items.top - item);
            JSON::Array::iterator it = array.begin();
            while (item < node->data.sequence.items.top) {
                convertNode(*it, yaml_document_get_node(&document, *item),
                    document);
                ++it; ++item;
            }
            break;
        }
        case YAML_MAPPING_NODE:
        {
            value = JSON::Object();
            JSON::Object &object = value.get<JSON::Object>();
            yaml_node_pair_t *pair = node->data.mapping.pairs.start;
            while (pair < node->data.mapping.pairs.top) {
                yaml_node_t *keyNode = yaml_document_get_node(&document,
                    pair->key);
                yaml_node_t *valueNode = yaml_document_get_node(&document,
                    pair->value);
                if (keyNode->type != YAML_SCALAR_NODE)
                    MORDOR_THROW_EXCEPTION(std::runtime_error("Can't use a non-string as a key"));
                std::string key((char *)keyNode->data.scalar.value,
                    keyNode->data.scalar.length);
                convertNode(object.insert(std::make_pair(key,
                    JSON::Value()))->second, valueNode, document);
                ++pair;
            }
            break;
        }
        default:
            MORDOR_NOTREACHED();
    }
}
Exemple #15
0
static bool hasOpenSSLError()
{
    unsigned long err = ERR_peek_error();
    if (err == SSL_ERROR_NONE)
        return false;
    switch (ERR_GET_REASON(err)) {
        case ERR_R_MALLOC_FAILURE:
            throw std::bad_alloc();
        case ERR_R_PASSED_NULL_PARAMETER:
            {
                char buf[120];
                ERR_error_string(err, buf);
                MORDOR_THROW_EXCEPTION(std::invalid_argument(buf));
            }
        default:
            return true;
    }
}
Exemple #16
0
void
SSLStream::serverNameIndication(const std::string &hostname)
{
    // Older versions of OpenSSL don't support this (I'm looking at you,
    // Leopard); just ignore it then
#ifdef SSL_set_tlsext_host_name
    std::lock_guard<std::mutex> lock(m_mutex);
    if (!SSL_set_tlsext_host_name(m_ssl.get(), hostname.c_str())) {
        if (!hasOpenSSLError()) return;
        std::string message = getOpenSSLErrorMessage();
        MORDOR_LOG_ERROR(g_log) << this << " SSL_set_tlsext_host_name("
            << m_ssl.get() << ", " << hostname.c_str() << "): " << message;
        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
          //  << boost::errinfo_api_function("SSL_set_tlsext_host_name");
        ;
    }
#endif
}
Exemple #17
0
std::string
Buffer::getDelimited(char delimiter, bool eofIsDelimiter, bool includeDelimiter)
{
    ptrdiff_t offset = find(delimiter, ~0);
    MORDOR_ASSERT(offset >= -1);
    if (offset == -1 && !eofIsDelimiter)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    eofIsDelimiter = offset == -1;
    if (offset == -1)
        offset = readAvailable();;
    std::string result;
    result.resize(offset + (eofIsDelimiter ? 0 : (includeDelimiter ? 1 : 0)));
    copyOut(&result[0], result.size());
    consume(result.size());
    if (!eofIsDelimiter && !includeDelimiter)
        consume(1u);
    return result;
}
Exemple #18
0
Multipart::ptr
BodyPart::multipart()
{
    if (m_childMultipart)
        return m_childMultipart;
    MORDOR_ASSERT(m_headers.contentType.type == "multipart");
    if (!m_stream) {
        MORDOR_ASSERT(m_multipart->m_stream->supportsWrite());
        std::ostringstream os;
        os << m_headers;
        std::string headers = os.str();
        m_multipart->m_stream->write(headers.c_str(), headers.size());
        NotifyStream *notify = new NotifyStream(m_multipart->m_stream, false);
        notify->notifyOnClose = boost::bind(&Multipart::partDone, m_multipart);
        m_stream.reset(notify);
    }
    HTTP::StringMap::const_iterator it = m_headers.contentType.parameters.find("boundary");
    if (it == m_headers.contentType.parameters.end()) {
        MORDOR_ASSERT(!m_multipart->m_stream->supportsWrite());
        MORDOR_THROW_EXCEPTION(InvalidMultipartBoundaryException());
    }
    m_childMultipart.reset(new Multipart(m_stream, it->second));
    return m_childMultipart;
}
Exemple #19
0
void
SSLStream::close(CloseType type)
{
    MORDOR_ASSERT(type == BOTH);
    if (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_SENT_SHUTDOWN)) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error);
        if (result <= 0) {
            MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get()
                << "): " << result << " (" << error << ")";
            switch (error) {
                case SSL_ERROR_NONE:
                case SSL_ERROR_ZERO_RETURN:
                    break;
                case SSL_ERROR_WANT_READ:
                case SSL_ERROR_WANT_WRITE:
                case SSL_ERROR_WANT_CONNECT:
                case SSL_ERROR_WANT_ACCEPT:
                case SSL_ERROR_WANT_X509_LOOKUP:
                    MORDOR_NOTREACHED();
                case SSL_ERROR_SYSCALL:
                    if (hasOpenSSLError()) {
                        std::string message = getOpenSSLErrorMessage();
                        MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                            << m_ssl.get() << "): " << result << " (" << error
                            << ", " << message << ")";
                        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                           // << boost::errinfo_api_function("SSL_shutdown");
                        ;
                    }
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ")";
                    if (result == 0)
                        break;
                    MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown");
                case SSL_ERROR_SSL:
                    {
                        MORDOR_ASSERT(hasOpenSSLError());
                        std::string message = getOpenSSLErrorMessage();
                        MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                            << m_ssl.get() << "): " << result << " (" << error
                            << ", " << message << ")";
                        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                          //  << boost::errinfo_api_function("SSL_shutdown");
                        ;
                    }
                default:
                    MORDOR_NOTREACHED();
            }
        }
        flush(false);
    }

    while (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_RECEIVED_SHUTDOWN)) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error);
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get()
            << "): " << result << " (" << error << ")";
        if (result > 0) {
            break;
        }
        switch (error) {
            case SSL_ERROR_NONE:
            case SSL_ERROR_ZERO_RETURN:
                break;
            case SSL_ERROR_WANT_READ:
                flush();
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_shutdown");
                    ;
                }
                MORDOR_LOG_WARNING(g_log) << this << " SSL_shutdown(" << m_ssl.get()
                    << "): " << result << " (" << error << ")";
                if (result == 0) {
                    break;
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_shutdown");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
        break;
    }
    parent()->close();
}
Exemple #20
0
void
SSLStream::connect()
{
    while (true) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_connect, m_ssl.get()), &error);
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_connect(" << m_ssl.get()
            << "): " << result << " (" << error << ")";
        if (result > 0) {
            flush(false);
            return;
        }
        switch (error) {
            case SSL_ERROR_NONE:
                flush(false);
                return;
            case SSL_ERROR_ZERO_RETURN:
                // Received close_notify message
                return;
            case SSL_ERROR_WANT_READ:
                flush();
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_connect");
                    ;
                }
                MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                    << m_ssl.get() << "): " << result << " (" << error
                    << ")";
                if (result == 0) {
                    MORDOR_THROW_EXCEPTION(UnexpectedEofException());
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_connect");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_connect");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Exemple #21
0
void authorize(const AuthParams &challenge, AuthParams &authorization,
               const URI &uri, const std::string &method, const std::string &username,
               const std::string &password)
{
    std::string realm, qop, nonce, opaque, algorithm;
    StringMap::const_iterator it;
    if ( (it = challenge.parameters.find("realm")) != challenge.parameters.end()) realm = it->second;
    if ( (it = challenge.parameters.find("qop")) != challenge.parameters.end()) qop = it->second;
    if ( (it = challenge.parameters.find("nonce")) != challenge.parameters.end()) nonce = it->second;
    if ( (it = challenge.parameters.find("opaque")) != challenge.parameters.end()) opaque = it->second;
    if ( (it = challenge.parameters.find("algorithm")) != challenge.parameters.end()) algorithm = it->second;

    if (algorithm.empty())
        algorithm = "MD5";
    StringSet qopValues;
    bool authQop = false;
    // If the server specified a quality of protection (qop), make sure it allows "auth"
    if (!qop.empty()) {
        ListParser parser(qopValues);
        parser.run(qop);
        if (parser.error() || !parser.complete())
            MORDOR_THROW_EXCEPTION(BadMessageHeaderException());
        if (qopValues.find("auth") == qopValues.end())
            MORDOR_THROW_EXCEPTION(InvalidQopException(qop));
        authQop = true;
    }

    // come up with a suitable client nonce
    std::ostringstream os;
    os << std::hex << TimerManager::now();
    std::string cnonce = os.str();
    std::string nc = "00000001";

    // compute A1
    std::string A1;
    if (algorithm == "MD5")
        A1 = username + ':' + realm + ':' + password;
    else if (algorithm == "MD5-sess")
        A1 = md5( username + ':' + realm + ':' + password ) + ':' + nonce + ':' + cnonce;
    else
        MORDOR_THROW_EXCEPTION(InvalidAlgorithmException(algorithm));

    // compute A2 - our qop is always auth or unspecified
    os.str("");
    os << method << ':' << uri;
    std::string A2 = os.str();

    authorization.scheme = "Digest";
    authorization.base64.clear();
    authorization.parameters["username"] = username;
    authorization.parameters["realm"] = realm;
    authorization.parameters["nonce"] = nonce;
    authorization.parameters["uri"] = uri.toString();
    authorization.parameters["algorithm"] = algorithm;

    std::string response;
    if (authQop) {
        qop = "auth";
        response = md5( md5(A1) + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + md5(A2) );
        authorization.parameters["qop"] = qop;
        authorization.parameters["nc"] = nc;
        authorization.parameters["cnonce"] = cnonce;
    } else {
        response = md5( md5(A1) + ':' + nonce + ':' + md5(A2) );

    }
    authorization.parameters["response"] = response;
    if (!opaque.empty())
        authorization.parameters["opaque"] = opaque;
}
Exemple #22
0
size_t
ZlibStream::read(Buffer &buffer, size_t length)
{
    if (m_closed)
        return 0;
    struct iovec outbuf = buffer.writeBuffer(length, false);
    m_strm.next_out = (Bytef*)outbuf.iov_base;
    m_strm.avail_out = outbuf.iov_len;

    while (true) {
        std::vector<iovec> inbufs = m_inBuffer.readBuffers();
        size_t avail_in;
        if (!inbufs.empty()) {
            m_strm.next_in = (Bytef*)inbufs[0].iov_base;
            avail_in = inbufs[0].iov_len;
            m_strm.avail_in = inbufs[0].iov_len;
        } else {
            m_strm.next_in = NULL;
            m_strm.avail_in = 0;
        }
        int rc = inflate(&m_strm, Z_NO_FLUSH);
        MORDOR_LOG_DEBUG(g_log) << this << " inflate(("
            << (inbufs.empty() ? 0 : inbufs[0].iov_len) << ", "
            << outbuf.iov_len << ")): " << rc << " (" << m_strm.avail_in
            << ", " << m_strm.avail_out << ")";
        if (!inbufs.empty())
            m_inBuffer.consume(inbufs[0].iov_len - m_strm.avail_in);
        size_t result;
        switch (rc) {
            case Z_STREAM_END:
                // May have still produced output
                result = outbuf.iov_len - m_strm.avail_out;
                buffer.produce(result);
                inflateEnd(&m_strm);
                m_closed = true;
                return result;
            case Z_OK:
                result = outbuf.iov_len - m_strm.avail_out;
                // It consumed input, but produced no output... DON'T return eof
                if (result == 0)
                    continue;
                buffer.produce(result);
                return result;
            case Z_BUF_ERROR:
                // no progress... we need to provide more input (since we're
                // guaranteed to provide output)
                MORDOR_ASSERT(m_strm.avail_in == 0);
                MORDOR_ASSERT(inbufs.empty());
                result = parent()->read(m_inBuffer, m_bufferSize);
                if (result == 0)
                    MORDOR_THROW_EXCEPTION(UnexpectedEofException());
                break;
            case Z_MEM_ERROR:
                throw std::bad_alloc();
            case Z_NEED_DICT:
                MORDOR_THROW_EXCEPTION(NeedPresetDictionaryException());
            case Z_DATA_ERROR:
                MORDOR_THROW_EXCEPTION(CorruptedZlibStreamException());
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Exemple #23
0
void
SSLStream::verifyPeerCertificate(const std::string &hostname)
{
    if (!hostname.empty()) {
        std::lock_guard<std::mutex> lock(m_mutex);
        std::string wildcardHostname = "*";
        size_t dot = hostname.find('.');
        if (dot != std::string::npos)
            wildcardHostname.append(hostname.substr(dot));
        std::shared_ptr<X509> cert;
        cert.reset(SSL_get_peer_certificate(m_ssl.get()), &X509_free);
        if (!cert)
            MORDOR_THROW_EXCEPTION(CertificateVerificationException(
                X509_V_ERR_APPLICATION_VERIFICATION,
                "No Certificate Presented"));
        int critical = -1, altNameIndex = -1;
        GENERAL_NAMES *gens = (GENERAL_NAMES *)X509_get_ext_d2i(cert.get(),
            NID_subject_alt_name, &critical, &altNameIndex);
        if (gens) {
            do {
                try {
                    bool success = false;
                    for(int i = 0; i < sk_GENERAL_NAME_num(gens); i++)
                    {
                        GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i);
                        if(gen->type != GEN_DNS) continue;
                        std::string altName((const char *)gen->d.dNSName->data,
                            gen->d.dNSName->length);
                        if (altName == wildcardHostname ||
                            altName == hostname) {
                            success = true;
                            break;
                        }
                    }
                    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
                    if (success)
                        return;
                } catch (...) {
                    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
                    throw;
                }
                gens = (GENERAL_NAMES *)X509_get_ext_d2i(cert.get(),
                    NID_subject_alt_name, &critical, &altNameIndex);
            } while (gens);
        }
        X509_NAME *name = X509_get_subject_name(cert.get());
        if (!name)
            MORDOR_THROW_EXCEPTION(CertificateVerificationException(
                X509_V_ERR_APPLICATION_VERIFICATION,
                "No Subject Name"));
        int len = X509_NAME_get_text_by_NID(name, NID_commonName, NULL, 0);
        if (len == -1)
            MORDOR_THROW_EXCEPTION(CertificateVerificationException(
                X509_V_ERR_APPLICATION_VERIFICATION,
                "No Common Name"));
        std::string commonName;
        commonName.resize(len);
        X509_NAME_get_text_by_NID(name, NID_commonName, &commonName[0],
            len + 1);
        if (commonName == wildcardHostname || commonName == hostname)
            return;
        MORDOR_THROW_EXCEPTION(CertificateVerificationException(
                X509_V_ERR_APPLICATION_VERIFICATION,
                "No Matching Common Name"));
    }
}
Exemple #24
0
Stream::ptr tunnel(HTTP::StreamBroker::ptr streamBroker, const URI &proxy,
    IPAddress::ptr targetIP, const std::string &targetDomain,
    unsigned short targetPort, unsigned char version)
{
    MORDOR_ASSERT(version == 4 || version == 5);
    MORDOR_ASSERT(version == 5 || !targetIP ||
        targetIP->family() == AF_INET);

    MORDOR_ASSERT(streamBroker);
    MORDOR_ASSERT(targetIP || !targetDomain.empty());
    std::string buffer;
    buffer.resize(std::max<size_t>(targetDomain.size() + 1u, 16u) + 9);

    Stream::ptr stream = streamBroker->getStream(proxy);
    if (version == 5) {
        buffer[0] = version;
        buffer[1] = 1;
        buffer[2] = 0;
        size_t written = 0;
        while (written < 3)
            written += stream->write(buffer.data() + written, 3 - written);
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 5)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if ((unsigned char)buffer[0] == 0xff)
            MORDOR_THROW_EXCEPTION(NoAcceptableAuthenticationMethodException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    }
    buffer[0] = version;
    buffer[1] = 1;
    size_t size;
    if (version == 4) {
        if (targetIP)
            *(unsigned short *)&buffer[2] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[2] = htons(targetPort);
        if (targetIP)
            *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
        else
            *(unsigned int *)&buffer[4] = htonl(0x00000001);
        buffer[8] = 0;
        if (!targetIP) {
            memcpy(&buffer[9], targetDomain.c_str(), targetDomain.size());
            buffer[9 + targetDomain.size()] = 0;
        }
        size = 9 + targetDomain.size() + (targetDomain.empty() ? 0 : 1);
    } else {
        buffer[2] = 0;
        if (targetIP) {
            if (targetIP->family() == AF_INET) {
                buffer[3] = 1;
                *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
                size = 7;
            } else {
                buffer[3] = 4;
                memcpy(&buffer[4], &((sockaddr_in6 *)targetIP->name())->sin6_addr, 16);
                size = 19;
            }
        } else {
            buffer[3] = 3;
            buffer[4] = (unsigned char)targetDomain.size();
            memcpy(&buffer[5], targetDomain.c_str(), targetDomain.size());
            size = 5 + targetDomain.size();
        }
        if (targetIP)
            *(unsigned short *)&buffer[size] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[size] = htons(targetPort);
        size += 2;
    }
    size_t written = 0;
    while (written < size)
        written += stream->write(buffer.data() + written, size - written);
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0) || (version == 5 && buffer[0] != 5))
        MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0x5a) || (version == 5 && buffer[0] != 0))
        MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
    if (version == 4) {
        size = 0;
        while (size < 6) {
            written = stream->read(&buffer[0], 6 - size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size += written;
        }
    } else {
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[1] == 3) {
            if (buffer[0] != 0)
                MORDOR_THROW_EXCEPTION(ProtocolViolationException());
            size = buffer[1] + 2;
        } else if (buffer[1] == 1) {
            size = 6;
        } else if (buffer[1] == 4) {
            size = 18;
        } else {
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        }
        while (size > 0) {
            written = stream->read(&buffer[0], size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size -= written;
        }
    }
    return stream;
}