Пример #1
0
// Parse an iterator to a python object.
static PyObject *py_iter_parse(qd_field_iterator_t *iter)
{
    qd_parsed_field_t *parsed=0;
    if (iter && (parsed = qd_parse(iter))) {
        if (!qd_parse_ok(parsed)) {
            qd_error(QD_ERROR_MESSAGE, qd_parse_error(parsed));
            qd_parse_free(parsed);
            return 0;
        }
        PyObject *value = qd_field_to_py(parsed);
        qd_parse_free(parsed);
        if (!value) qd_error_py();
        return value;
    }
    qd_error(QD_ERROR_MESSAGE, "Failed to parse message field");
    return 0;
}
Пример #2
0
/// Return NULL and set qd_error if not a valid bit.
static const level_t* level_for_bit(int bit) {
    level_index_t i = 0;
    while (i < N_LEVELS && levels[i].bit != bit) ++i;
    if (i == N_LEVELS) {
        qd_error(QD_ERROR_CONFIG, "'%d' is not a valid log level bit.", bit);
        return NULL;
    }
    return &levels[i];
}
Пример #3
0
/// Return NULL and set qd_error if not a valid level.
static const level_t* level_for_name(const char *name, int len) {
    level_index_t i = 0;
    while (i < N_LEVELS && strncasecmp(levels[i].name, name, len) != 0) ++i;
    if (i == N_LEVELS) {
        qd_error(QD_ERROR_CONFIG, "'%s' is not a valid log level. Should be one of {%s}.",
                 name, level_names);
        return NULL;
    }
    return &levels[i];
}
Пример #4
0
qd_error_t qd_dispatch_validate_config(const char *config_path)
{
    FILE* config_file = NULL;
    char config_data = '\0';
    qd_error_t validation_error = QD_ERROR_CONFIG;

    do {
        if (!config_path) {
            validation_error = qd_error(QD_ERROR_VALUE, "Configuration path value was empty");
            break;
        }

        config_file = fopen(config_path, "r");
        if (!config_file) {
            validation_error = qd_error(QD_ERROR_NOT_FOUND, "Configuration file could not be opened");
            break;
        }

        // TODO Check the actual minimum number of bytes required for the smallest valid configuration file
        if (!fread((void*)&config_data, 1, 1, config_file)) {
            validation_error = qd_error(QD_ERROR_CONFIG, "Configuration file was empty");
            break;
        }

        // TODO Add real validation code

        validation_error = QD_ERROR_NONE;
    } while (false); // do once

    if (config_file)
    {
        fclose(config_file);
    }

    return validation_error;
}
Пример #5
0
qd_error_t qd_dispatch_load_config(qd_dispatch_t *qd, const char *config_path)
{
    qd->dl_handle = dlopen(QPID_DISPATCH_LIB, RTLD_LAZY | RTLD_NOLOAD);
    if (!qd->dl_handle)
        return qd_error(QD_ERROR_RUNTIME, "Cannot locate library %s", QPID_DISPATCH_LIB);

    qd_python_lock_state_t lock_state = qd_python_lock();
    PyObject *module = PyImport_ImportModule("qpid_dispatch_internal.management.config");
    PyObject *configure_dispatch = module ? PyObject_GetAttrString(module, "configure_dispatch") : NULL;
    Py_XDECREF(module);
    PyObject *result = configure_dispatch ? PyObject_CallFunction(configure_dispatch, "(lls)", (long)qd, qd->dl_handle, config_path) : NULL;
    Py_XDECREF(configure_dispatch);
    if (!result) qd_error_py();
    Py_XDECREF(result);
    qd_python_unlock(lock_state);
    return qd_error_code();
}
Пример #6
0
static void qd_config_ssl_profile_process_password(qd_config_ssl_profile_t* ssl_profile)
{
    char *pw = ssl_profile->ssl_password;
    if (!pw)
        return;

    //
    // If the "password" starts with "env:" then the remaining
    // text is the environment variable that contains the password
    //
    if (strncmp(pw, "env:", 4) == 0) {
        char *env = pw + 4;
        // skip the leading whitespace if it is there
        while (*env == ' ') ++env;

        const char* passwd = getenv(env);
        if (passwd) {
            //
            // Replace the allocated directive with the looked-up password
            //
            free(ssl_profile->ssl_password);
            ssl_profile->ssl_password = strdup(passwd);
        } else {
            qd_error(QD_ERROR_NOT_FOUND, "Failed to find a password in the environment variable");
        }
    }

    //
    // If the "password" starts with "literal:" then
    // the remaining text is the password and the heading should be
    // stripped off
    //
    else if (strncmp(pw, "literal:", 8) == 0) {
        // skip the "literal:" header
        pw += 8;

        // skip the whitespace if it is there
        while (*pw == ' ') ++pw;

        // Replace the password with a copy of the string after "literal:"
        char *copy = strdup(pw);
        free(ssl_profile->ssl_password);
        ssl_profile->ssl_password = copy;
    }
}
Пример #7
0
qd_error_t qd_entity_configure_policy(qd_policy_t *policy, qd_entity_t *entity)
{
    policy->max_connection_limit = qd_entity_opt_long(entity, "maximumConnections", 0); CHECK();
    if (policy->max_connection_limit < 0)
        return qd_error(QD_ERROR_CONFIG, "maximumConnections must be >= 0");
    policy->policyFolder =
        qd_entity_opt_string(entity, "policyFolder", 0); CHECK();
    policy->enableAccessRules = qd_entity_opt_bool(entity, "enableAccessRules", false); CHECK();
    qd_log(policy->log_source, QD_LOG_INFO, "Policy configured maximumConnections: %d, policyFolder: '%s', access rules enabled: '%s'",
           policy->max_connection_limit, policy->policyFolder, (policy->enableAccessRules ? "true" : "false"));
    return QD_ERROR_NONE;

error:
    if (policy->policyFolder)
        free(policy->policyFolder);
    qd_policy_free(policy);
    return qd_error_code();
}
Пример #8
0
// Copy a message field, using to_py to a python object attribute.
static qd_error_t iter_to_py_attr(qd_field_iterator_t *iter,
                                  PyObject* (*to_py)(qd_field_iterator_t *),
                                  PyObject *obj, const char *attr)
{
    qd_error_clear();
    if (iter) {
        PyObject *value = to_py(iter);
        qd_field_iterator_free(iter);
        if (value) {
            PyObject_SetAttrString(obj, attr, value);
            Py_DECREF(value);
        }
        else {
            qd_error_py();      /* In case there were python errors. */
            qd_error(QD_ERROR_MESSAGE, "Can't convert message field %s", attr);
        }
    }
    return qd_error_code();
}
Пример #9
0
qd_error_t qd_dispatch_configure_auto_link(qd_dispatch_t *qd, qd_entity_t *entity) {
    if (!qd->router) return qd_error(QD_ERROR_NOT_FOUND, "No router available");
    qd_router_configure_auto_link(qd->router, entity);
    return qd_error_code();
}
Пример #10
0
static bool qd_message_check_LH(qd_message_content_t *content, qd_message_depth_t depth)
{
    qd_error_clear();
    qd_buffer_t *buffer  = DEQ_HEAD(content->buffers);

    if (!buffer) {
        qd_error(QD_ERROR_MESSAGE, "No data");
        return false;
    }

    if (depth <= content->parse_depth)
        return true; // We've already parsed at least this deep

    if (content->parse_buffer == 0) {
        content->parse_buffer = buffer;
        content->parse_cursor = qd_buffer_base(content->parse_buffer);
    }

    if (depth == QD_DEPTH_NONE)
        return true;

    //
    // MESSAGE HEADER
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_HEADER,
                               MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST, &content->section_message_header, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid header");
        return false;
    }
    if (depth == QD_DEPTH_HEADER)
        return true;

    //
    // DELIVERY ANNOTATION
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS,
                               DELIVERY_ANNOTATION_LONG, DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid delivery-annotations");
        return false;
    }
    if (depth == QD_DEPTH_DELIVERY_ANNOTATIONS)
        return true;

    //
    // MESSAGE ANNOTATION
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS,
                               MESSAGE_ANNOTATION_LONG, MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid annotations");
        return false;
    }
    if (depth == QD_DEPTH_MESSAGE_ANNOTATIONS)
        return true;

    //
    // PROPERTIES
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_PROPERTIES,
                               PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST, &content->section_message_properties, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid message properties");
        return false;
    }
    if (depth == QD_DEPTH_PROPERTIES)
        return true;

    //
    // APPLICATION PROPERTIES
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_APPLICATION_PROPERTIES,
                               APPLICATION_PROPERTIES_LONG, APPLICATION_PROPERTIES_SHORT, TAGS_MAP, &content->section_application_properties, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid application-properties");
        return false;
    }
    if (depth == QD_DEPTH_APPLICATION_PROPERTIES)
        return true;

    //
    // BODY
    // Note that this function expects a limited set of types in a VALUE section.  This is
    // not a problem for messages passing through Dispatch because through-only messages won't
    // be parsed to BODY-depth.
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
                               BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY, &content->section_body, 1)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid body data");
        return false;
    }
    if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
                               BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, TAGS_LIST, &content->section_body, 1)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid body sequence");
        return false;
    }
    if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
                               BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY, &content->section_body, 0)) {
        qd_error(QD_ERROR_MESSAGE, "Invalid body value");
        return false;
    }
    if (depth == QD_DEPTH_BODY)
        return true;

    //
    // FOOTER
    //
    if (0 == qd_check_field_LH(content, QD_DEPTH_ALL,
                               FOOTER_LONG, FOOTER_SHORT, TAGS_MAP, &content->section_footer, 0)) {

        qd_error(QD_ERROR_MESSAGE, "Invalid footer");
        return false;
    }

    return true;
}
Пример #11
0
qd_error_t qd_py_to_composed(PyObject *value, qd_composed_field_t *field)
{
    qd_python_check_lock();
    qd_error_clear();
    if (value == Py_None) {
        qd_compose_insert_null(field);
    }
    else if (PyBool_Check(value)) {
        qd_compose_insert_bool(field, PyInt_AS_LONG(value) ? 1 : 0);
    }
    else if (PyInt_Check(value)) {
        qd_compose_insert_long(field, (int64_t) PyInt_AS_LONG(value));
    }
    else if (PyLong_Check(value)) {
        qd_compose_insert_long(field, (int64_t) PyLong_AsLongLong(value));
    }
    else if (PyString_Check(value) || PyUnicode_Check(value)) {
        qd_compose_insert_string(field, PyString_AsString(value));
    }
    else if (PyDict_Check(value)) {
        Py_ssize_t  iter = 0;
        PyObject   *key;
        PyObject   *val;
        qd_compose_start_map(field);
        while (PyDict_Next(value, &iter, &key, &val)) {
            qd_py_to_composed(key, field); QD_ERROR_RET();
            qd_py_to_composed(val, field); QD_ERROR_RET();
        }
        QD_ERROR_PY_RET();
        qd_compose_end_map(field);
    }

    else if (PyList_Check(value)) {
        Py_ssize_t count = PyList_Size(value);
        if (count == 0)
            qd_compose_empty_list(field);
        else {
            qd_compose_start_list(field);
            for (Py_ssize_t idx = 0; idx < count; idx++) {
                PyObject *item = PyList_GetItem(value, idx); QD_ERROR_PY_RET();
                qd_py_to_composed(item, field); QD_ERROR_RET();
            }
            qd_compose_end_list(field);
        }
    }

    else if (PyTuple_Check(value)) {
        Py_ssize_t count = PyTuple_Size(value);
        if (count == 0)
            qd_compose_empty_list(field);
        else {
            qd_compose_start_list(field);
            for (Py_ssize_t idx = 0; idx < count; idx++) {
                PyObject *item = PyTuple_GetItem(value, idx); QD_ERROR_PY_RET();
                qd_py_to_composed(item, field); QD_ERROR_RET();
            }
            qd_compose_end_list(field);
        }
    }
    else {
        PyObject *type=0, *typestr=0, *repr=0;
        if ((type = PyObject_Type(value)) &&
            (typestr = PyObject_Str(type)) &&
            (repr = PyObject_Repr(value)))
            qd_error(QD_ERROR_TYPE, "Can't compose object of type %s: %s",
                     PyString_AsString(typestr), PyString_AsString(repr));
        else
            qd_error(QD_ERROR_TYPE, "Can't compose python object of unknown type");

        Py_XDECREF(type);
        Py_XDECREF(typestr);
        Py_XDECREF(repr);
    }
    return qd_error_code();
}
Пример #12
0
static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *config, qd_entity_t* entity, bool is_listener)
{
    qd_error_clear();

    bool authenticatePeer   = qd_entity_opt_bool(entity, "authenticatePeer",  false);    CHECK();
    bool verifyHostName     = qd_entity_opt_bool(entity, "verifyHostName",    true);     CHECK();
    bool requireEncryption  = qd_entity_opt_bool(entity, "requireEncryption", false);    CHECK();
    bool requireSsl         = qd_entity_opt_bool(entity, "requireSsl",        false);    CHECK();

    memset(config, 0, sizeof(*config));
    config->log_message          = qd_entity_opt_string(entity, "logMessage", 0);     CHECK();
    config->log_bits             = populate_log_message(config);
    config->port                 = qd_entity_get_string(entity, "port");              CHECK();
    config->name                 = qd_entity_opt_string(entity, "name", 0);           CHECK();
    config->role                 = qd_entity_get_string(entity, "role");              CHECK();
    config->inter_router_cost    = qd_entity_opt_long(entity, "cost", 1);             CHECK();
    config->protocol_family      = qd_entity_opt_string(entity, "protocolFamily", 0); CHECK();
    config->http                 = qd_entity_opt_bool(entity, "http", false);         CHECK();
    config->http_root            = qd_entity_opt_string(entity, "httpRoot", false);   CHECK();
    config->http = config->http || config->http_root; /* httpRoot implies http */
    config->max_frame_size       = qd_entity_get_long(entity, "maxFrameSize");        CHECK();
    config->max_sessions         = qd_entity_get_long(entity, "maxSessions");         CHECK();
    uint64_t ssn_frames          = qd_entity_opt_long(entity, "maxSessionFrames", 0); CHECK();
    config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds");  CHECK();
    if (is_listener) {
        config->initial_handshake_timeout_seconds = qd_entity_get_long(entity, "initialHandshakeTimeoutSeconds");  CHECK();
    }
    config->sasl_username        = qd_entity_opt_string(entity, "saslUsername", 0);   CHECK();
    config->sasl_password        = qd_entity_opt_string(entity, "saslPassword", 0);   CHECK();
    config->sasl_mechanisms      = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK();
    config->ssl_profile          = qd_entity_opt_string(entity, "sslProfile", 0);     CHECK();
    config->sasl_plugin          = qd_entity_opt_string(entity, "saslPlugin", 0);   CHECK();
    config->link_capacity        = qd_entity_opt_long(entity, "linkCapacity", 0);     CHECK();
    config->multi_tenant         = qd_entity_opt_bool(entity, "multiTenant", false);  CHECK();
    set_config_host(config, entity);

    //
    // Handle the defaults for various settings
    //
    if (config->link_capacity == 0)
        config->link_capacity = 250;

    if (config->max_sessions == 0 || config->max_sessions > 32768)
        // Proton disallows > 32768
        config->max_sessions = 32768;

    if (config->max_frame_size < QD_AMQP_MIN_MAX_FRAME_SIZE)
        // Silently promote the minimum max-frame-size
        // Proton will do this but the number is needed for the
        // incoming capacity calculation.
        config->max_frame_size = QD_AMQP_MIN_MAX_FRAME_SIZE;

    //
    // Given session frame count and max frame size compute session incoming_capacity
    //
    if (ssn_frames == 0)
        config->incoming_capacity = (sizeof(size_t) < 8) ? 0x7FFFFFFFLL : 0x7FFFFFFFLL * config->max_frame_size;
    else {
        uint64_t mfs      = (uint64_t) config->max_frame_size;
        uint64_t trial_ic = ssn_frames * mfs;
        uint64_t limit    = (sizeof(size_t) < 8) ? (1ll << 31) - 1 : 0;
        if (limit == 0 || trial_ic < limit) {
            // Silently promote incoming capacity of zero to one
            config->incoming_capacity = 
                (trial_ic < QD_AMQP_MIN_MAX_FRAME_SIZE ? QD_AMQP_MIN_MAX_FRAME_SIZE : trial_ic);
        } else {
            config->incoming_capacity = limit;
            uint64_t computed_ssn_frames = limit / mfs;
            qd_log(qd->connection_manager->log_source, QD_LOG_WARNING,
                   "Server configuation for I/O adapter entity name:'%s', host:'%s', port:'%s', "
                   "requested maxSessionFrames truncated from %"PRId64" to %"PRId64,
                   config->name, config->host, config->port, ssn_frames, computed_ssn_frames);
        }
    }

    //
    // For now we are hardwiring this attribute to true.  If there's an outcry from the
    // user community, we can revisit this later.
    //
    config->allowInsecureAuthentication = true;
    config->verify_host_name = verifyHostName;

    char *stripAnnotations  = qd_entity_opt_string(entity, "stripAnnotations", 0);
    load_strip_annotations(config, stripAnnotations);
    free(stripAnnotations);
    stripAnnotations = 0;
    CHECK();

    config->requireAuthentication = authenticatePeer;
    config->requireEncryption     = requireEncryption || requireSsl;

    if (config->ssl_profile) {
        config->ssl_required = requireSsl;
        config->ssl_require_peer_authentication = config->sasl_mechanisms &&
            strstr(config->sasl_mechanisms, "EXTERNAL") != 0;

        qd_config_ssl_profile_t *ssl_profile =
            qd_find_ssl_profile(qd->connection_manager, config->ssl_profile);
        if (ssl_profile) {
            config->ssl_certificate_file = SSTRDUP(ssl_profile->ssl_certificate_file);
            config->ssl_private_key_file = SSTRDUP(ssl_profile->ssl_private_key_file);
            config->ciphers = SSTRDUP(ssl_profile->ciphers);
            config->ssl_password = SSTRDUP(ssl_profile->ssl_password);
            config->ssl_trusted_certificate_db = SSTRDUP(ssl_profile->ssl_trusted_certificate_db);
            config->ssl_trusted_certificates = SSTRDUP(ssl_profile->ssl_trusted_certificates);
            config->ssl_uid_format = SSTRDUP(ssl_profile->ssl_uid_format);
            config->ssl_display_name_file = SSTRDUP(ssl_profile->ssl_display_name_file);
        }
    }

    if (config->sasl_plugin) {
        qd_config_sasl_plugin_t *sasl_plugin =
            qd_find_sasl_plugin(qd->connection_manager, config->sasl_plugin);
        if (sasl_plugin) {
            config->auth_service = SSTRDUP(sasl_plugin->auth_service);
            config->sasl_init_hostname = SSTRDUP(sasl_plugin->sasl_init_hostname);
            qd_log(qd->connection_manager->log_source, QD_LOG_INFO, "Using auth service %s from  SASL Plugin %s", config->auth_service, config->sasl_plugin);

            if (sasl_plugin->auth_ssl_profile) {
                qd_config_ssl_profile_t *auth_ssl_profile =
                    qd_find_ssl_profile(qd->connection_manager, sasl_plugin->auth_ssl_profile);
                config->auth_ssl_conf = pn_ssl_domain(PN_SSL_MODE_CLIENT);

                if (auth_ssl_profile->ssl_certificate_file) {
                    if (pn_ssl_domain_set_credentials(config->auth_ssl_conf,
                                                      auth_ssl_profile->ssl_certificate_file,
                                                      auth_ssl_profile->ssl_private_key_file,
                                                      auth_ssl_profile->ssl_password)) {
                        qd_error(QD_ERROR_RUNTIME, "Cannot set SSL credentials for authentication service"); CHECK();
                    }
                }
                if (auth_ssl_profile->ssl_trusted_certificate_db) {
                    if (pn_ssl_domain_set_trusted_ca_db(config->auth_ssl_conf, auth_ssl_profile->ssl_trusted_certificate_db)) {
                        qd_error(QD_ERROR_RUNTIME, "Cannot set trusted SSL certificate db for authentication service" ); CHECK();
                    } else {
                        if (pn_ssl_domain_set_peer_authentication(config->auth_ssl_conf, PN_SSL_VERIFY_PEER, auth_ssl_profile->ssl_trusted_certificate_db)) {
                            qd_error(QD_ERROR_RUNTIME, "Cannot set SSL peer verification for authentication service"); CHECK();
                        }
                    }
                }
                if (auth_ssl_profile->ciphers) {
                    if (pn_ssl_domain_set_ciphers(config->auth_ssl_conf, auth_ssl_profile->ciphers)) {
                        return qd_error(QD_ERROR_RUNTIME, "Cannot set ciphers. The ciphers string might be invalid. Use openssl ciphers -v <ciphers> to validate");
                    }
                }

            }
        } else {
            qd_error(QD_ERROR_RUNTIME, "Cannot find sasl plugin %s", config->sasl_plugin); CHECK();
        }
    }

    return QD_ERROR_NONE;

  error:
    qd_server_config_free(config);
    return qd_error_code();
}