// 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; }
/// 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]; }
/// 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]; }
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; }
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(); }
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; } }
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(); }
// 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(); }
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(); }
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; }
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(); }
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(); }