From 4f61f5d9eec75e471c8176dac0c21f4361e40ee6 Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Thu, 11 Sep 2014 12:33:05 +0200 Subject: [LIBREPORT PATCH 67/93] ureport: use additional HTTP headers with 'rhsm-entitlement' cert auth Related to rhbz#1140224 Signed-off-by: Jakub Filak Conflicts: src/plugins/ureport.conf --- src/lib/json.c | 29 +++++++++++---- src/lib/ureport.h | 1 + src/plugins/ureport.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- src/plugins/ureport.conf | 4 ++- 4 files changed, 119 insertions(+), 9 deletions(-) diff --git a/src/lib/json.c b/src/lib/json.c index 8935ef8..6fbbf39 100644 --- a/src/lib/json.c +++ b/src/lib/json.c @@ -113,14 +113,25 @@ struct post_state *post_ureport(const char *json, struct ureport_server_config * post_state->client_key_path = config->ur_client_key; } - static const char *headers[] = { - "Accept: application/json", - "Connection: close", - NULL, - }; + char **headers = xmalloc(sizeof(char *) * (3 + size_map_string(config->ur_http_headers))); + headers[0] = (char *)"Accept: application/json"; + headers[1] = (char *)"Connection: close"; + headers[2] = NULL; + + if (config->ur_http_headers != NULL) + { + unsigned i = 2; + const char *header; + const char *value; + map_string_iter_t iter; + init_map_string_iter(&iter, config->ur_http_headers); + while (next_map_string_iter(&iter, &header, &value)) + headers[i++] = xasprintf("%s: %s", header, value); + headers[i] = NULL; + } post_string_as_form_data(post_state, config->ur_url, "application/json", - headers, json); + (const char **)headers, json); /* Client authentication failed. Try again without client auth. * CURLE_SSL_CONNECT_ERROR - cert not found/server doesnt trust the CA @@ -135,10 +146,14 @@ struct post_state *post_ureport(const char *json, struct ureport_server_config * post_state = new_post_state(flags); post_string_as_form_data(post_state, config->ur_url, "application/json", - headers, json); + (const char **)headers, json); } + for (unsigned i = size_map_string(config->ur_http_headers); i != 0; --i) + free(headers[i + 1]); + free(headers); + return post_state; } diff --git a/src/lib/ureport.h b/src/lib/ureport.h index ca1d538..319aca9 100644 --- a/src/lib/ureport.h +++ b/src/lib/ureport.h @@ -43,6 +43,7 @@ struct ureport_server_config char *ur_client_cert; ///< Path to certificate used for client ///< authentication (or NULL) char *ur_client_key; ///< Private key for the certificate + map_string_t *ur_http_headers; ///< Additional HTTP headers struct ureport_preferences ur_prefs; ///< configuration for uReport generation }; diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c index d23cc79..9c69cad 100644 --- a/src/plugins/ureport.c +++ b/src/plugins/ureport.c @@ -31,6 +31,12 @@ #define RHSM_CERT_PATH "/etc/pki/consumer/cert.pem" #define RHSM_KEY_PATH "/etc/pki/consumer/key.pem" +#define RHAP_PEM_DIR_PATH "/etc/pki/entitlement" +#define RHAP_ENT_DATA_BEGIN_TAG "-----BEGIN ENTITLEMENT DATA-----" +#define RHAP_ENT_DATA_END_TAG "-----END ENTITLEMENT DATA-----" +#define RHAP_SIG_DATA_BEGIN_TAG "-----BEGIN RSA SIGNATURE-----" +#define RHAP_SIG_DATA_END_TAG "-----END RSA SIGNATURE-----" + #define VALUE_FROM_CONF(opt, var, tr) do { const char *value = getenv("uReport_"opt); \ if (!value) { value = get_map_string_item_or_NULL(settings, opt); } if (value) { var = tr(value); } \ } while(0) @@ -72,6 +78,88 @@ static void parse_client_auth_paths(struct ureport_server_config *config, const config->ur_client_cert = xstrdup(RHSM_CERT_PATH); config->ur_client_key = xstrdup(RHSM_KEY_PATH); } + else if (strcmp(client_auth, "rhsm-entitlement") == 0) + { + GList *certs = get_file_list(RHAP_PEM_DIR_PATH, "pem"); + if (g_list_length(certs) != 2) + { + log_notice(RHAP_PEM_DIR_PATH" does not contain unique cert-key files pair"); + log_notice("Not using client authentication"); + return; + } + + const char *cert = NULL; + const char *key = NULL; + + file_obj_t *fst = (file_obj_t *)certs->data; + file_obj_t *scn = (file_obj_t *)certs->next->data; + + if (strlen(fo_get_filename(fst)) < strlen(fo_get_filename(scn))) + { + cert = fo_get_filename(fst); + key = fo_get_filename(scn); + + config->ur_client_cert = xstrdup(fo_get_fullpath(fst)); + config->ur_client_key = xstrdup(fo_get_fullpath(scn)); + } + else + { + cert = fo_get_filename(scn); + key = fo_get_filename(fst); + + config->ur_client_cert = xstrdup(fo_get_fullpath(scn)); + config->ur_client_key = xstrdup(fo_get_fullpath(fst)); + } + + const bool iscomplement = prefixcmp(key, cert) != 0 || strcmp("-key", key + strlen(cert)) != 0; + g_list_free_full(certs, (GDestroyNotify)free_file_obj); + + if (iscomplement) + { + log_notice("Key file '%s' isn't complement to cert file '%s'", + config->ur_client_key, config->ur_client_cert); + log_notice("Not using client authentication"); + + free(config->ur_client_cert); + free(config->ur_client_key); + config->ur_client_cert = NULL; + config->ur_client_key = NULL; + + return; + } + + char *certdata = xmalloc_open_read_close(config->ur_client_cert, /*no size limit*/NULL); + if (certdata != NULL) + { + char *ent_data = xstrdup_between(certdata, + RHAP_ENT_DATA_BEGIN_TAG, RHAP_ENT_DATA_END_TAG); + + char *sig_data = xstrdup_between(certdata, + RHAP_SIG_DATA_BEGIN_TAG, RHAP_SIG_DATA_END_TAG); + + if (ent_data != NULL && sig_data != NULL) + { + ent_data = strremovech(ent_data, '\n'); + insert_map_string(config->ur_http_headers, + xstrdup("X-RH-Entitlement-Data"), + xasprintf(RHAP_ENT_DATA_BEGIN_TAG"%s"RHAP_ENT_DATA_END_TAG, ent_data)); + + sig_data = strremovech(sig_data, '\n'); + insert_map_string(config->ur_http_headers, + xstrdup("X-RH-Entitlement-Sig"), + xasprintf(RHAP_SIG_DATA_BEGIN_TAG"%s"RHAP_SIG_DATA_END_TAG, sig_data)); + } + else + { + log_notice("Cert file '%s' doesn't contain Entitlement and RSA Signature sections", config->ur_client_cert); + log_notice("Not using HTTP authentication headers"); + } + + free(sig_data); + free(ent_data); + free(certdata); + } + } else if (strcmp(client_auth, "puppet") == 0) { config->ur_client_cert = puppet_config_print("hostcert"); @@ -83,7 +171,6 @@ static void parse_client_auth_paths(struct ureport_server_config *config, const config->ur_client_cert = xstrdup(strtok(scratch, ":")); config->ur_client_key = xstrdup(strtok(NULL, ":")); free(scratch); - if (config->ur_client_cert == NULL || config->ur_client_key == NULL) error_msg_and_die("Invalid client authentication specification"); } @@ -426,11 +513,14 @@ int main(int argc, char **argv) .ur_ssl_verify = true, .ur_client_cert = NULL, .ur_client_key = NULL, + .ur_http_headers = NULL, { .urp_auth_items = NULL, }, }; + config.ur_http_headers = new_map_string(); + enum { OPT_v = 1 << 0, OPT_d = 1 << 1, @@ -677,6 +767,8 @@ finalize: if (config.ur_prefs.urp_auth_items != auth_items) g_list_free_full(config.ur_prefs.urp_auth_items, free); + free_map_string(config.ur_http_headers); + free_map_string(settings); free(config.ur_client_cert); free(config.ur_client_key); diff --git a/src/plugins/ureport.conf b/src/plugins/ureport.conf index 8abeb26..fc0dc21 100644 --- a/src/plugins/ureport.conf +++ b/src/plugins/ureport.conf @@ -19,7 +19,9 @@ AuthDataItems = hostname, machineid # None (default): # SSLClientAuth = # Using RH subscription management certificate: -SSLClientAuth = rhsm +# SSLClientAuth = rhsm +# Using RH subscription management entitlement certificate: +# SSLClientAuth = rhsm-entitlement # Using Puppet certificate: # SSLClientAuth = puppet # Using custom certificate: -- 1.8.3.1