You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2200 lines
73 KiB
2200 lines
73 KiB
5 years ago
|
From e67393a38e1739ff1b0453fdb3b68ff7e4fb36e9 Mon Sep 17 00:00:00 2001
|
||
|
From: Jakub Filak <jfilak@redhat.com>
|
||
|
Date: Fri, 12 Sep 2014 17:20:01 +0200
|
||
|
Subject: [LIBREPORT PATCH 79/93] ureport: publish ureport.h and refactore
|
||
|
uReport source
|
||
|
|
||
|
Allow other plugins to submit uReport and allow external applications to
|
||
|
use libreport to submit uReport.
|
||
|
|
||
|
Related to rhbz1139987
|
||
|
|
||
|
Signed-off-by: Jakub Filak <jfilak@redhat.com>
|
||
|
---
|
||
|
src/include/Makefile.am | 4 +
|
||
|
src/include/ureport.h | 76 ++++
|
||
|
src/lib/Makefile.am | 4 +-
|
||
|
src/lib/json.c | 180 ----------
|
||
|
src/lib/ureport.c | 180 ++++++++++
|
||
|
src/lib/ureport.h | 76 ----
|
||
|
src/plugins/Makefile.am | 4 +-
|
||
|
src/plugins/reporter-ureport.c | 777 +++++++++++++++++++++++++++++++++++++++++
|
||
|
src/plugins/ureport.c | 777 -----------------------------------------
|
||
|
9 files changed, 1043 insertions(+), 1035 deletions(-)
|
||
|
create mode 100644 src/include/ureport.h
|
||
|
delete mode 100644 src/lib/json.c
|
||
|
create mode 100644 src/lib/ureport.c
|
||
|
delete mode 100644 src/lib/ureport.h
|
||
|
create mode 100644 src/plugins/reporter-ureport.c
|
||
|
delete mode 100644 src/plugins/ureport.c
|
||
|
|
||
|
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
|
||
|
index 806b93e..de44cda 100644
|
||
|
--- a/src/include/Makefile.am
|
||
|
+++ b/src/include/Makefile.am
|
||
|
@@ -15,3 +15,7 @@ libreport_include_HEADERS = \
|
||
|
internal_libreport.h \
|
||
|
internal_abrt_dbus.h \
|
||
|
xml_parser.h
|
||
|
+
|
||
|
+if BUILD_UREPORT
|
||
|
+libreport_include_HEADERS += ureport.h
|
||
|
+endif
|
||
|
diff --git a/src/include/ureport.h b/src/include/ureport.h
|
||
|
new file mode 100644
|
||
|
index 0000000..d341f6e
|
||
|
--- /dev/null
|
||
|
+++ b/src/include/ureport.h
|
||
|
@@ -0,0 +1,76 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2012 ABRT team
|
||
|
+ Copyright (C) 2012 RedHat Inc
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or modify
|
||
|
+ it under the terms of the GNU General Public License as published by
|
||
|
+ the Free Software Foundation; either version 2 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ GNU General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License along
|
||
|
+ with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+#ifndef UREPORT_H_
|
||
|
+#define UREPORT_H_
|
||
|
+
|
||
|
+#include "problem_data.h"
|
||
|
+
|
||
|
+#ifdef __cplusplus
|
||
|
+extern "C" {
|
||
|
+#endif
|
||
|
+
|
||
|
+/*
|
||
|
+ * uReport generation configuration
|
||
|
+ */
|
||
|
+struct ureport_preferences
|
||
|
+{
|
||
|
+ GList *urp_auth_items; ///< list of file names included in 'auth' key
|
||
|
+};
|
||
|
+
|
||
|
+/*
|
||
|
+ * uReport server configuration
|
||
|
+ */
|
||
|
+struct ureport_server_config
|
||
|
+{
|
||
|
+ const char *ur_url; ///< Web service URL
|
||
|
+ bool ur_ssl_verify; ///< Verify HOST and PEER certificates
|
||
|
+ 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
|
||
|
+};
|
||
|
+
|
||
|
+struct abrt_post_state;
|
||
|
+
|
||
|
+#define ureport_post libreport_ureport_post
|
||
|
+struct post_state *ureport_post(const char *json_ureport,
|
||
|
+ struct ureport_server_config *config);
|
||
|
+
|
||
|
+#define ureport_attach_rhbz libreport_ureport_attach_rhbz
|
||
|
+struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
|
||
|
+ struct ureport_server_config *config);
|
||
|
+
|
||
|
+#define ureport_attach_email libreport_ureport_attach_email
|
||
|
+struct post_state *ureport_attach_email(const char *bthash, const char *email,
|
||
|
+ struct ureport_server_config *config);
|
||
|
+
|
||
|
+#define ureport_from_dump_dir libreport_ureport_from_dump_dir
|
||
|
+char *ureport_from_dump_dir(const char *dump_dir_path);
|
||
|
+
|
||
|
+#define ureport_from_dump_dir_ext libreport_ureport_from_dump_dir_ext
|
||
|
+char *ureport_from_dump_dir_ext(const char *dump_dir_path,
|
||
|
+ const struct ureport_preferences *preferences);
|
||
|
+
|
||
|
+#ifdef __cplusplus
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+#endif
|
||
|
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
|
||
|
index d2ff675..7d9722a 100644
|
||
|
--- a/src/lib/Makefile.am
|
||
|
+++ b/src/lib/Makefile.am
|
||
|
@@ -72,6 +72,7 @@ libreport_la_CPPFLAGS = \
|
||
|
-DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \
|
||
|
-DDUMP_DIR_OWNED_BY_USER=$(DUMP_DIR_OWNED_BY_USER) \
|
||
|
-DLARGE_DATA_TMP_DIR=\"$(LARGE_DATA_TMP_DIR)\" \
|
||
|
+ $(JSON_C_CFLAGS) \
|
||
|
$(GLIB_CFLAGS) \
|
||
|
$(GOBJECT_CFLAGS) \
|
||
|
$(AUGEAS_CFLAGS) \
|
||
|
@@ -79,6 +80,7 @@ libreport_la_CPPFLAGS = \
|
||
|
libreport_la_LDFLAGS = \
|
||
|
-version-info 0:1:0
|
||
|
libreport_la_LIBADD = \
|
||
|
+ $(JSON_C_LIBS) \
|
||
|
$(GLIB_LIBS) \
|
||
|
$(JOURNAL_LIBS) \
|
||
|
$(GOBJECT_LIBS) \
|
||
|
@@ -113,7 +115,7 @@ libreport_web_o += abrt_xmlrpc.h abrt_xmlrpc.c
|
||
|
endif
|
||
|
|
||
|
if BUILD_UREPORT
|
||
|
-libreport_web_o += ureport.h json.c
|
||
|
+libreport_web_o += ureport.c
|
||
|
endif
|
||
|
|
||
|
libreport_web_la_SOURCES = $(libreport_web_o) \
|
||
|
diff --git a/src/lib/json.c b/src/lib/json.c
|
||
|
deleted file mode 100644
|
||
|
index 6fbbf39..0000000
|
||
|
--- a/src/lib/json.c
|
||
|
+++ /dev/null
|
||
|
@@ -1,180 +0,0 @@
|
||
|
-/*
|
||
|
- Copyright (C) 2012 ABRT team
|
||
|
- Copyright (C) 2012 RedHat Inc
|
||
|
-
|
||
|
- This program is free software; you can redistribute it and/or modify
|
||
|
- it under the terms of the GNU General Public License as published by
|
||
|
- the Free Software Foundation; either version 2 of the License, or
|
||
|
- (at your option) any later version.
|
||
|
-
|
||
|
- This program is distributed in the hope that it will be useful,
|
||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
- GNU General Public License for more details.
|
||
|
-
|
||
|
- You should have received a copy of the GNU General Public License along
|
||
|
- with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
-*/
|
||
|
-
|
||
|
-#include <json/json.h>
|
||
|
-
|
||
|
-#include <satyr/abrt.h>
|
||
|
-#include <satyr/report.h>
|
||
|
-
|
||
|
-#include "internal_libreport.h"
|
||
|
-#include "ureport.h"
|
||
|
-#include "libreport_curl.h"
|
||
|
-
|
||
|
-
|
||
|
-static void ureport_add_str(struct json_object *ur, const char *key,
|
||
|
- const char *s)
|
||
|
-{
|
||
|
- struct json_object *jstring = json_object_new_string(s);
|
||
|
- if (!jstring)
|
||
|
- die_out_of_memory();
|
||
|
-
|
||
|
- json_object_object_add(ur, key, jstring);
|
||
|
-}
|
||
|
-
|
||
|
-char *ureport_from_dump_dir_ext(const char *dump_dir_path, const struct ureport_preferences *preferences)
|
||
|
-{
|
||
|
- char *error_message;
|
||
|
- struct sr_report *report = sr_abrt_report_from_dir(dump_dir_path,
|
||
|
- &error_message);
|
||
|
-
|
||
|
- if (!report)
|
||
|
- error_msg_and_die("%s", error_message);
|
||
|
-
|
||
|
- if (preferences != NULL && preferences->urp_auth_items != NULL)
|
||
|
- {
|
||
|
- struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
|
||
|
- if (!dd)
|
||
|
- xfunc_die(); /* dd_opendir() already printed an error message */
|
||
|
-
|
||
|
- GList *iter = preferences->urp_auth_items;
|
||
|
- for ( ; iter != NULL; iter = g_list_next(iter))
|
||
|
- {
|
||
|
- const char *key = (const char *)iter->data;
|
||
|
- char *value = dd_load_text_ext(dd, key,
|
||
|
- DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
|
||
|
-
|
||
|
- if (value == NULL)
|
||
|
- {
|
||
|
- perror_msg("Cannot include '%s' in 'auth'", key);
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- sr_report_add_auth(report, key, value);
|
||
|
- }
|
||
|
-
|
||
|
- dd_close(dd);
|
||
|
- }
|
||
|
-
|
||
|
- char *json_ureport = sr_report_to_json(report);
|
||
|
- sr_report_free(report);
|
||
|
-
|
||
|
- return json_ureport;
|
||
|
-}
|
||
|
-
|
||
|
-char *ureport_from_dump_dir(const char *dump_dir_path)
|
||
|
-{
|
||
|
- return ureport_from_dump_dir_ext(dump_dir_path, /*no preferences*/NULL);
|
||
|
-}
|
||
|
-
|
||
|
-char *new_json_attachment(const char *bthash, const char *type, const char *data)
|
||
|
-{
|
||
|
- struct json_object *attachment = json_object_new_object();
|
||
|
- if (!attachment)
|
||
|
- die_out_of_memory();
|
||
|
-
|
||
|
- ureport_add_str(attachment, "bthash", bthash);
|
||
|
- ureport_add_str(attachment, "type", type);
|
||
|
- ureport_add_str(attachment, "data", data);
|
||
|
-
|
||
|
- char *result = xstrdup(json_object_to_json_string(attachment));
|
||
|
- json_object_put(attachment);
|
||
|
-
|
||
|
- return result;
|
||
|
-}
|
||
|
-
|
||
|
-struct post_state *post_ureport(const char *json, struct ureport_server_config *config)
|
||
|
-{
|
||
|
- int flags = POST_WANT_BODY | POST_WANT_ERROR_MSG;
|
||
|
-
|
||
|
- if (config->ur_ssl_verify)
|
||
|
- flags |= POST_WANT_SSL_VERIFY;
|
||
|
-
|
||
|
- struct post_state *post_state = new_post_state(flags);
|
||
|
-
|
||
|
- if (config->ur_client_cert && config->ur_client_key)
|
||
|
- {
|
||
|
- post_state->client_cert_path = config->ur_client_cert;
|
||
|
- post_state->client_key_path = config->ur_client_key;
|
||
|
- }
|
||
|
-
|
||
|
- 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",
|
||
|
- (const char **)headers, json);
|
||
|
-
|
||
|
- /* Client authentication failed. Try again without client auth.
|
||
|
- * CURLE_SSL_CONNECT_ERROR - cert not found/server doesnt trust the CA
|
||
|
- * CURLE_SSL_CERTPROBLEM - malformed certificate/no permission
|
||
|
- */
|
||
|
- if ((post_state->curl_result == CURLE_SSL_CONNECT_ERROR
|
||
|
- || post_state->curl_result == CURLE_SSL_CERTPROBLEM)
|
||
|
- && config->ur_client_cert && config->ur_client_key)
|
||
|
- {
|
||
|
- warn_msg("Authentication failed. Retrying unauthenticated.");
|
||
|
- free_post_state(post_state);
|
||
|
- post_state = new_post_state(flags);
|
||
|
-
|
||
|
- post_string_as_form_data(post_state, config->ur_url, "application/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;
|
||
|
-}
|
||
|
-
|
||
|
-struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
|
||
|
- struct ureport_server_config *config)
|
||
|
-{
|
||
|
- char *str_bug_id = xasprintf("%d", rhbz_bug_id);
|
||
|
- char *json_attachment = new_json_attachment(bthash, "RHBZ", str_bug_id);
|
||
|
- struct post_state *post_state = post_ureport(json_attachment, config);
|
||
|
- free(str_bug_id);
|
||
|
- free(json_attachment);
|
||
|
-
|
||
|
- return post_state;
|
||
|
-}
|
||
|
-
|
||
|
-struct post_state *ureport_attach_email(const char *bthash, const char *email,
|
||
|
- struct ureport_server_config *config)
|
||
|
-{
|
||
|
- char *json_attachment = new_json_attachment(bthash, "email", email);
|
||
|
- struct post_state *post_state = post_ureport(json_attachment, config);
|
||
|
- free(json_attachment);
|
||
|
-
|
||
|
- return post_state;
|
||
|
-}
|
||
|
diff --git a/src/lib/ureport.c b/src/lib/ureport.c
|
||
|
new file mode 100644
|
||
|
index 0000000..761fe62
|
||
|
--- /dev/null
|
||
|
+++ b/src/lib/ureport.c
|
||
|
@@ -0,0 +1,180 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2012,2014 ABRT team
|
||
|
+ Copyright (C) 2012,2014 RedHat Inc
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or modify
|
||
|
+ it under the terms of the GNU General Public License as published by
|
||
|
+ the Free Software Foundation; either version 2 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ GNU General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License along
|
||
|
+ with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+
|
||
|
+#include <json.h>
|
||
|
+
|
||
|
+#include <satyr/abrt.h>
|
||
|
+#include <satyr/report.h>
|
||
|
+
|
||
|
+#include "internal_libreport.h"
|
||
|
+#include "ureport.h"
|
||
|
+#include "libreport_curl.h"
|
||
|
+
|
||
|
+
|
||
|
+static void ureport_add_str(struct json_object *ur, const char *key,
|
||
|
+ const char *s)
|
||
|
+{
|
||
|
+ struct json_object *jstring = json_object_new_string(s);
|
||
|
+ if (!jstring)
|
||
|
+ die_out_of_memory();
|
||
|
+
|
||
|
+ json_object_object_add(ur, key, jstring);
|
||
|
+}
|
||
|
+
|
||
|
+char *ureport_from_dump_dir_ext(const char *dump_dir_path, const struct ureport_preferences *preferences)
|
||
|
+{
|
||
|
+ char *error_message;
|
||
|
+ struct sr_report *report = sr_abrt_report_from_dir(dump_dir_path,
|
||
|
+ &error_message);
|
||
|
+
|
||
|
+ if (!report)
|
||
|
+ error_msg_and_die("%s", error_message);
|
||
|
+
|
||
|
+ if (preferences != NULL && preferences->urp_auth_items != NULL)
|
||
|
+ {
|
||
|
+ struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
|
||
|
+ if (!dd)
|
||
|
+ xfunc_die(); /* dd_opendir() already printed an error message */
|
||
|
+
|
||
|
+ GList *iter = preferences->urp_auth_items;
|
||
|
+ for ( ; iter != NULL; iter = g_list_next(iter))
|
||
|
+ {
|
||
|
+ const char *key = (const char *)iter->data;
|
||
|
+ char *value = dd_load_text_ext(dd, key,
|
||
|
+ DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
|
||
|
+
|
||
|
+ if (value == NULL)
|
||
|
+ {
|
||
|
+ perror_msg("Cannot include '%s' in 'auth'", key);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ sr_report_add_auth(report, key, value);
|
||
|
+ }
|
||
|
+
|
||
|
+ dd_close(dd);
|
||
|
+ }
|
||
|
+
|
||
|
+ char *json_ureport = sr_report_to_json(report);
|
||
|
+ sr_report_free(report);
|
||
|
+
|
||
|
+ return json_ureport;
|
||
|
+}
|
||
|
+
|
||
|
+char *ureport_from_dump_dir(const char *dump_dir_path)
|
||
|
+{
|
||
|
+ return ureport_from_dump_dir_ext(dump_dir_path, /*no preferences*/NULL);
|
||
|
+}
|
||
|
+
|
||
|
+static char *new_json_attachment(const char *bthash, const char *type, const char *data)
|
||
|
+{
|
||
|
+ struct json_object *attachment = json_object_new_object();
|
||
|
+ if (!attachment)
|
||
|
+ die_out_of_memory();
|
||
|
+
|
||
|
+ ureport_add_str(attachment, "bthash", bthash);
|
||
|
+ ureport_add_str(attachment, "type", type);
|
||
|
+ ureport_add_str(attachment, "data", data);
|
||
|
+
|
||
|
+ char *result = xstrdup(json_object_to_json_string(attachment));
|
||
|
+ json_object_put(attachment);
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+struct post_state *ureport_post(const char *json, struct ureport_server_config *config)
|
||
|
+{
|
||
|
+ int flags = POST_WANT_BODY | POST_WANT_ERROR_MSG;
|
||
|
+
|
||
|
+ if (config->ur_ssl_verify)
|
||
|
+ flags |= POST_WANT_SSL_VERIFY;
|
||
|
+
|
||
|
+ struct post_state *post_state = new_post_state(flags);
|
||
|
+
|
||
|
+ if (config->ur_client_cert && config->ur_client_key)
|
||
|
+ {
|
||
|
+ post_state->client_cert_path = config->ur_client_cert;
|
||
|
+ post_state->client_key_path = config->ur_client_key;
|
||
|
+ }
|
||
|
+
|
||
|
+ 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",
|
||
|
+ (const char **)headers, json);
|
||
|
+
|
||
|
+ /* Client authentication failed. Try again without client auth.
|
||
|
+ * CURLE_SSL_CONNECT_ERROR - cert not found/server doesnt trust the CA
|
||
|
+ * CURLE_SSL_CERTPROBLEM - malformed certificate/no permission
|
||
|
+ */
|
||
|
+ if ((post_state->curl_result == CURLE_SSL_CONNECT_ERROR
|
||
|
+ || post_state->curl_result == CURLE_SSL_CERTPROBLEM)
|
||
|
+ && config->ur_client_cert && config->ur_client_key)
|
||
|
+ {
|
||
|
+ warn_msg("Authentication failed. Retrying unauthenticated.");
|
||
|
+ free_post_state(post_state);
|
||
|
+ post_state = new_post_state(flags);
|
||
|
+
|
||
|
+ post_string_as_form_data(post_state, config->ur_url, "application/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;
|
||
|
+}
|
||
|
+
|
||
|
+struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
|
||
|
+ struct ureport_server_config *config)
|
||
|
+{
|
||
|
+ char *str_bug_id = xasprintf("%d", rhbz_bug_id);
|
||
|
+ char *json_attachment = new_json_attachment(bthash, "RHBZ", str_bug_id);
|
||
|
+ struct post_state *post_state = ureport_post(json_attachment, config);
|
||
|
+ free(str_bug_id);
|
||
|
+ free(json_attachment);
|
||
|
+
|
||
|
+ return post_state;
|
||
|
+}
|
||
|
+
|
||
|
+struct post_state *ureport_attach_email(const char *bthash, const char *email,
|
||
|
+ struct ureport_server_config *config)
|
||
|
+{
|
||
|
+ char *json_attachment = new_json_attachment(bthash, "email", email);
|
||
|
+ struct post_state *post_state = ureport_post(json_attachment, config);
|
||
|
+ free(json_attachment);
|
||
|
+
|
||
|
+ return post_state;
|
||
|
+}
|
||
|
diff --git a/src/lib/ureport.h b/src/lib/ureport.h
|
||
|
deleted file mode 100644
|
||
|
index 319aca9..0000000
|
||
|
--- a/src/lib/ureport.h
|
||
|
+++ /dev/null
|
||
|
@@ -1,76 +0,0 @@
|
||
|
-/*
|
||
|
- Copyright (C) 2012 ABRT team
|
||
|
- Copyright (C) 2012 RedHat Inc
|
||
|
-
|
||
|
- This program is free software; you can redistribute it and/or modify
|
||
|
- it under the terms of the GNU General Public License as published by
|
||
|
- the Free Software Foundation; either version 2 of the License, or
|
||
|
- (at your option) any later version.
|
||
|
-
|
||
|
- This program is distributed in the hope that it will be useful,
|
||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
- GNU General Public License for more details.
|
||
|
-
|
||
|
- You should have received a copy of the GNU General Public License along
|
||
|
- with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
-*/
|
||
|
-#ifndef UREPORT_H_
|
||
|
-#define UREPORT_H_
|
||
|
-
|
||
|
-#include "problem_data.h"
|
||
|
-
|
||
|
-#ifdef __cplusplus
|
||
|
-extern "C" {
|
||
|
-#endif
|
||
|
-
|
||
|
-/*
|
||
|
- * uReport generation configuration
|
||
|
- */
|
||
|
-struct ureport_preferences
|
||
|
-{
|
||
|
- GList *urp_auth_items; ///< list of file names included in 'auth' key
|
||
|
-};
|
||
|
-
|
||
|
-/*
|
||
|
- * uReport server configuration
|
||
|
- */
|
||
|
-struct ureport_server_config
|
||
|
-{
|
||
|
- const char *ur_url; ///< Web service URL
|
||
|
- bool ur_ssl_verify; ///< Verify HOST and PEER certificates
|
||
|
- 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
|
||
|
-};
|
||
|
-
|
||
|
-struct abrt_post_state;
|
||
|
-
|
||
|
-#define post_ureport libreport_post_ureport
|
||
|
-struct post_state *post_ureport(const char *json_ureport,
|
||
|
- struct ureport_server_config *config);
|
||
|
-
|
||
|
-#define ureport_attach_rhbz libreport_ureport_attach_rhbz
|
||
|
-struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
|
||
|
- struct ureport_server_config *config);
|
||
|
-
|
||
|
-#define ureport_attach_email libreport_ureport_attach_email
|
||
|
-struct post_state *ureport_attach_email(const char *bthash, const char *email,
|
||
|
- struct ureport_server_config *config);
|
||
|
-
|
||
|
-#define ureport_from_dump_dir libreport_ureport_from_dump_dir
|
||
|
-char *ureport_from_dump_dir(const char *dump_dir_path);
|
||
|
-
|
||
|
-#define ureport_from_dump_dir_ext libreport_ureport_from_dump_dir_ext
|
||
|
-char *ureport_from_dump_dir_ext(const char *dump_dir_path,
|
||
|
- const struct ureport_preferences *preferences);
|
||
|
-
|
||
|
-#ifdef __cplusplus
|
||
|
-}
|
||
|
-#endif
|
||
|
-
|
||
|
-#endif
|
||
|
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
|
||
|
index 7ec5219..7ec08d7 100644
|
||
|
--- a/src/plugins/Makefile.am
|
||
|
+++ b/src/plugins/Makefile.am
|
||
|
@@ -250,15 +250,17 @@ endif
|
||
|
|
||
|
if BUILD_UREPORT
|
||
|
reporter_ureport_SOURCES = \
|
||
|
- ureport.c
|
||
|
+ reporter-ureport.c
|
||
|
reporter_ureport_CPPFLAGS = \
|
||
|
-I$(srcdir)/../include \
|
||
|
-I$(srcdir)/../lib \
|
||
|
+ $(JSON_C_CFLAGS) \
|
||
|
$(GLIB_CFLAGS) \
|
||
|
$(LIBREPORT_CFLAGS) \
|
||
|
-DPLUGINS_CONF_DIR=\"$(REPORT_PLUGINS_CONF_DIR)\" \
|
||
|
-D_GNU_SOURCE
|
||
|
reporter_ureport_LDADD = \
|
||
|
+ $(JSON_C_LIBS) \
|
||
|
../lib/libreport.la \
|
||
|
../lib/libreport-web.la
|
||
|
endif
|
||
|
diff --git a/src/plugins/reporter-ureport.c b/src/plugins/reporter-ureport.c
|
||
|
new file mode 100644
|
||
|
index 0000000..d827c7d
|
||
|
--- /dev/null
|
||
|
+++ b/src/plugins/reporter-ureport.c
|
||
|
@@ -0,0 +1,777 @@
|
||
|
+/*
|
||
|
+ Copyright (C) 2012 ABRT Team
|
||
|
+ Copyright (C) 2012 RedHat inc.
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or modify
|
||
|
+ it under the terms of the GNU General Public License as published by
|
||
|
+ the Free Software Foundation; either version 2 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ GNU General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License along
|
||
|
+ with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+*/
|
||
|
+
|
||
|
+#include <json.h>
|
||
|
+#include "internal_libreport.h"
|
||
|
+#include "ureport.h"
|
||
|
+#include "libreport_curl.h"
|
||
|
+
|
||
|
+#define CONF_FILE_PATH PLUGINS_CONF_DIR"/ureport.conf"
|
||
|
+
|
||
|
+#define REPORT_URL_SFX "reports/new/"
|
||
|
+#define ATTACH_URL_SFX "reports/attach/"
|
||
|
+#define BTHASH_URL_SFX "reports/bthash/"
|
||
|
+
|
||
|
+#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)
|
||
|
+
|
||
|
+static char *puppet_config_print(const char *key)
|
||
|
+{
|
||
|
+ char *command = xasprintf("puppet config print %s", key);
|
||
|
+ char *result = run_in_shell_and_save_output(0, command, NULL, NULL);
|
||
|
+ free(command);
|
||
|
+
|
||
|
+ /* run_in_shell_and_save_output always returns non-NULL */
|
||
|
+ if (result[0] != '/')
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ char *newline = strchrnul(result, '\n');
|
||
|
+ if (!newline)
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ *newline = '\0';
|
||
|
+ return result;
|
||
|
+error:
|
||
|
+ free(result);
|
||
|
+ error_msg_and_die("Unable to determine puppet %s path (puppet not installed?)", key);
|
||
|
+}
|
||
|
+
|
||
|
+static void parse_client_auth_paths(struct ureport_server_config *config, const char *client_auth)
|
||
|
+{
|
||
|
+ if (client_auth == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (strcmp(client_auth, "") == 0)
|
||
|
+ {
|
||
|
+ config->ur_client_cert = NULL;
|
||
|
+ config->ur_client_key = NULL;
|
||
|
+ log_notice("Not using client authentication");
|
||
|
+ }
|
||
|
+ else if (strcmp(client_auth, "rhsm") == 0)
|
||
|
+ {
|
||
|
+ 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");
|
||
|
+ config->ur_client_key = puppet_config_print("hostprivkey");
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ char *scratch = xstrdup(client_auth);
|
||
|
+ 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");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (config->ur_client_cert && config->ur_client_key)
|
||
|
+ {
|
||
|
+ log_notice("Using client certificate: %s", config->ur_client_cert);
|
||
|
+ log_notice("Using client private key: %s", config->ur_client_key);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Loads uReport configuration from various sources.
|
||
|
+ *
|
||
|
+ * Replaces a value of an already configured option only if the
|
||
|
+ * option was found in a configuration source.
|
||
|
+ *
|
||
|
+ * @param config a server configuration to be populated
|
||
|
+ */
|
||
|
+static void load_ureport_server_config(struct ureport_server_config *config, map_string_t *settings)
|
||
|
+{
|
||
|
+ VALUE_FROM_CONF("URL", config->ur_url, (const char *));
|
||
|
+ VALUE_FROM_CONF("SSLVerify", config->ur_ssl_verify, string_to_bool);
|
||
|
+
|
||
|
+ bool include_auth = false;
|
||
|
+ VALUE_FROM_CONF("IncludeAuthData", include_auth, string_to_bool);
|
||
|
+
|
||
|
+ if (include_auth)
|
||
|
+ {
|
||
|
+ const char *auth_items = NULL;
|
||
|
+ VALUE_FROM_CONF("AuthDataItems", auth_items, (const char *));
|
||
|
+ config->ur_prefs.urp_auth_items = parse_list(auth_items);
|
||
|
+
|
||
|
+ if (config->ur_prefs.urp_auth_items == NULL)
|
||
|
+ log_warning("IncludeAuthData set to 'yes' but AuthDataItems is empty.");
|
||
|
+ }
|
||
|
+
|
||
|
+ const char *client_auth = NULL;
|
||
|
+ VALUE_FROM_CONF("SSLClientAuth", client_auth, (const char *));
|
||
|
+ parse_client_auth_paths(config, client_auth);
|
||
|
+}
|
||
|
+
|
||
|
+struct ureport_server_response {
|
||
|
+ bool is_error;
|
||
|
+ char *value;
|
||
|
+ char *message;
|
||
|
+ char *bthash;
|
||
|
+ GList *reported_to_list;
|
||
|
+ char *solution;
|
||
|
+};
|
||
|
+
|
||
|
+void free_ureport_server_response(struct ureport_server_response *resp)
|
||
|
+{
|
||
|
+ if (!resp)
|
||
|
+ return;
|
||
|
+
|
||
|
+ free(resp->solution);
|
||
|
+ g_list_free_full(resp->reported_to_list, g_free);
|
||
|
+ free(resp->bthash);
|
||
|
+ free(resp->message);
|
||
|
+ free(resp->value);
|
||
|
+ free(resp);
|
||
|
+}
|
||
|
+
|
||
|
+static char *parse_solution_from_json_list(struct json_object *list, GList **reported_to)
|
||
|
+{
|
||
|
+ json_object *list_elem, *struct_elem;
|
||
|
+ const char *cause, *note, *url;
|
||
|
+ struct strbuf *solution_buf = strbuf_new();
|
||
|
+
|
||
|
+ const unsigned length = json_object_array_length(list);
|
||
|
+
|
||
|
+ const char *one_format = _("Your problem seems to be caused by %s\n\n%s\n");
|
||
|
+ if (length > 1)
|
||
|
+ {
|
||
|
+ strbuf_append_str(solution_buf, _("Your problem seems to be caused by one of the following:\n"));
|
||
|
+ one_format = "\n* %s\n\n%s\n";
|
||
|
+ }
|
||
|
+
|
||
|
+ bool empty = true;
|
||
|
+ for (unsigned i = 0; i < length; ++i)
|
||
|
+ {
|
||
|
+ list_elem = json_object_array_get_idx(list, i);
|
||
|
+ if (!list_elem)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "cause", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ cause = json_object_get_string(struct_elem);
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "note", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ note = json_object_get_string(struct_elem);
|
||
|
+ if (!note)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ empty = false;
|
||
|
+ strbuf_append_strf(solution_buf, one_format, cause, note);
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "url", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ url = json_object_get_string(struct_elem);
|
||
|
+ if (url)
|
||
|
+ {
|
||
|
+ char *reported_to_line = xasprintf("%s: URL=%s", cause, url);
|
||
|
+ *reported_to = g_list_append(*reported_to, reported_to_line);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (empty)
|
||
|
+ {
|
||
|
+ strbuf_free(solution_buf);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return strbuf_free_nobuf(solution_buf);
|
||
|
+}
|
||
|
+
|
||
|
+/* reported_to json element should be a list of structures
|
||
|
+{ "reporter": "Bugzilla",
|
||
|
+ "type": "url",
|
||
|
+ "value": "https://bugzilla.redhat.com/show_bug.cgi?id=XYZ" } */
|
||
|
+static GList *parse_reported_to_from_json_list(struct json_object *list)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ json_object *list_elem, *struct_elem;
|
||
|
+ const char *reporter, *value, *type;
|
||
|
+ char *reported_to_line, *prefix;
|
||
|
+ GList *result = NULL;
|
||
|
+
|
||
|
+ for (i = 0; i < json_object_array_length(list); ++i)
|
||
|
+ {
|
||
|
+ prefix = NULL;
|
||
|
+ list_elem = json_object_array_get_idx(list, i);
|
||
|
+ if (!list_elem)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "reporter", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ reporter = json_object_get_string(struct_elem);
|
||
|
+ if (!reporter)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "value", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ value = json_object_get_string(struct_elem);
|
||
|
+ if (!value)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!json_object_object_get_ex(list_elem, "type", &struct_elem))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ type = json_object_get_string(struct_elem);
|
||
|
+ if (type)
|
||
|
+ {
|
||
|
+ if (strcasecmp("url", type) == 0)
|
||
|
+ prefix = xstrdup("URL=");
|
||
|
+ else if (strcasecmp("bthash", type) == 0)
|
||
|
+ prefix = xstrdup("BTHASH=");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!prefix)
|
||
|
+ prefix = xstrdup("");
|
||
|
+
|
||
|
+ reported_to_line = xasprintf("%s: %s%s", reporter, prefix, value);
|
||
|
+ free(prefix);
|
||
|
+
|
||
|
+ result = g_list_append(result, reported_to_line);
|
||
|
+ }
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Reponse samples:
|
||
|
+ * {"error":"field 'foo' is required"}
|
||
|
+ * {"response":"true"}
|
||
|
+ * {"response":"false"}
|
||
|
+ */
|
||
|
+static struct ureport_server_response *ureport_server_parse_json(json_object *json)
|
||
|
+{
|
||
|
+ json_object *obj = NULL;
|
||
|
+ if (json_object_object_get_ex(json, "error", &obj))
|
||
|
+ {
|
||
|
+ struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
|
||
|
+ out_response->is_error = true;
|
||
|
+ /*
|
||
|
+ * Used to use json_object_to_json_string(obj), but it returns
|
||
|
+ * the string in quote marks (") - IOW, json-formatted string.
|
||
|
+ */
|
||
|
+ out_response->value = xstrdup(json_object_get_string(obj));
|
||
|
+ return out_response;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (json_object_object_get_ex(json, "result", &obj))
|
||
|
+ {
|
||
|
+ struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
|
||
|
+ out_response->value = xstrdup(json_object_get_string(obj));
|
||
|
+
|
||
|
+ json_object *message = NULL;
|
||
|
+ if (json_object_object_get_ex(json, "message", &message))
|
||
|
+ out_response->message = xstrdup(json_object_get_string(message));
|
||
|
+
|
||
|
+ json_object *bthash = NULL;
|
||
|
+ if (json_object_object_get_ex(json, "bthash", &bthash))
|
||
|
+ out_response->bthash = xstrdup(json_object_get_string(bthash));
|
||
|
+
|
||
|
+ json_object *reported_to_list = NULL;
|
||
|
+ if (json_object_object_get_ex(json, "reported_to", &reported_to_list))
|
||
|
+ out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
|
||
|
+
|
||
|
+ json_object *solutions = NULL;
|
||
|
+ if (json_object_object_get_ex(json, "solutions", &solutions))
|
||
|
+ out_response->solution = parse_solution_from_json_list(solutions, &(out_response->reported_to_list));
|
||
|
+
|
||
|
+ return out_response;
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static struct ureport_server_response *get_server_response(post_state_t *post_state, struct ureport_server_config *config)
|
||
|
+{
|
||
|
+ /* Previously, the condition here was (post_state->errmsg[0] != '\0')
|
||
|
+ * however when the server asks for optional client authentication and we do not have the certificates,
|
||
|
+ * then post_state->errmsg contains "NSS: client certificate not found (nickname not specified)" even though
|
||
|
+ * the request succeeded.
|
||
|
+ */
|
||
|
+ if (post_state->curl_result != CURLE_OK)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed to upload uReport to the server '%s' with curl: %s"), config->ur_url, post_state->errmsg);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (post_state->http_resp_code == 404)
|
||
|
+ {
|
||
|
+ error_msg(_("The URL '%s' does not exist (got error 404 from server)"), config->ur_url);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (post_state->http_resp_code == 500)
|
||
|
+ {
|
||
|
+ error_msg(_("The server at '%s' encountered an internal error (got error 500)"), config->ur_url);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (post_state->http_resp_code == 503)
|
||
|
+ {
|
||
|
+ error_msg(_("The server at '%s' currently can't handle the request (got error 503)"), config->ur_url);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (post_state->http_resp_code != 202
|
||
|
+ && post_state->http_resp_code != 400
|
||
|
+ && post_state->http_resp_code != 413)
|
||
|
+ {
|
||
|
+ /* can't print better error message */
|
||
|
+ error_msg(_("Unexpected HTTP response from '%s': %d"), config->ur_url, post_state->http_resp_code);
|
||
|
+ log_notice("%s", post_state->body);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ json_object *const json = json_tokener_parse(post_state->body);
|
||
|
+
|
||
|
+ if (is_error(json))
|
||
|
+ {
|
||
|
+ error_msg(_("Unable to parse response from ureport server at '%s'"), config->ur_url);
|
||
|
+ log_notice("%s", post_state->body);
|
||
|
+ json_object_put(json);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ struct ureport_server_response *response = ureport_server_parse_json(json);
|
||
|
+ json_object_put(json);
|
||
|
+
|
||
|
+ if (!response)
|
||
|
+ error_msg(_("The response from '%s' has invalid format"), config->ur_url);
|
||
|
+ else if ((post_state->http_resp_code == 202 && response->is_error)
|
||
|
+ || (post_state->http_resp_code != 202 && !response->is_error))
|
||
|
+ {
|
||
|
+ /* HTTP CODE 202 means that call was successful but the response */
|
||
|
+ /* has an error message */
|
||
|
+ error_msg(_("Type mismatch has been detected in the response from '%s'"), config->ur_url);
|
||
|
+ }
|
||
|
+
|
||
|
+ return response;
|
||
|
+}
|
||
|
+
|
||
|
+typedef post_state_t *(*attach_handler)(const char *, void *, struct ureport_server_config *);
|
||
|
+
|
||
|
+static post_state_t *wrp_ureport_attach_rhbz(const char *ureport_hash, int *rhbz_bug,
|
||
|
+ struct ureport_server_config *config)
|
||
|
+{
|
||
|
+ return ureport_attach_rhbz(ureport_hash, *rhbz_bug, config);
|
||
|
+}
|
||
|
+
|
||
|
+static bool perform_attach(struct ureport_server_config *config, const char *ureport_hash,
|
||
|
+ attach_handler handler, void *args)
|
||
|
+{
|
||
|
+ char *dest_url = concat_path_file(config->ur_url, ATTACH_URL_SFX);
|
||
|
+ const char *old_url = config->ur_url;
|
||
|
+ config->ur_url = dest_url;
|
||
|
+ post_state_t *post_state = handler(ureport_hash, args, config);
|
||
|
+ config->ur_url = old_url;
|
||
|
+ free(dest_url);
|
||
|
+
|
||
|
+ struct ureport_server_response *resp = get_server_response(post_state, config);
|
||
|
+ free_post_state(post_state);
|
||
|
+ /* don't use str_bo_bool() because we require "true" string */
|
||
|
+ const int result = !resp || resp->is_error || strcmp(resp->value,"true") != 0;
|
||
|
+
|
||
|
+ if (resp && resp->is_error)
|
||
|
+ {
|
||
|
+ error_msg(_("The server at '%s' responded with an error: '%s'"), config->ur_url, resp->value);
|
||
|
+ }
|
||
|
+
|
||
|
+ free_ureport_server_response(resp);
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char **argv)
|
||
|
+{
|
||
|
+ setlocale(LC_ALL, "");
|
||
|
+#if ENABLE_NLS
|
||
|
+ bindtextdomain(PACKAGE, LOCALEDIR);
|
||
|
+ textdomain(PACKAGE);
|
||
|
+#endif
|
||
|
+
|
||
|
+ abrt_init(argv);
|
||
|
+
|
||
|
+ struct ureport_server_config config = {
|
||
|
+ .ur_url = NULL,
|
||
|
+ .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,
|
||
|
+ OPT_u = 1 << 2,
|
||
|
+ OPT_k = 1 << 3,
|
||
|
+ OPT_t = 1 << 4,
|
||
|
+ OPT_i = 1 << 5,
|
||
|
+ };
|
||
|
+
|
||
|
+ int ret = 1; /* "failure" (for now) */
|
||
|
+ bool insecure = !config.ur_ssl_verify;
|
||
|
+ const char *conf_file = CONF_FILE_PATH;
|
||
|
+ const char *arg_server_url = NULL;
|
||
|
+ const char *client_auth = NULL;
|
||
|
+ GList *auth_items = NULL;
|
||
|
+ const char *dump_dir_path = ".";
|
||
|
+ const char *ureport_hash = NULL;
|
||
|
+ bool ureport_hash_from_rt = false;
|
||
|
+ int rhbz_bug = -1;
|
||
|
+ bool rhbz_bug_from_rt = false;
|
||
|
+ const char *email_address = NULL;
|
||
|
+ bool email_address_from_env = false;
|
||
|
+ struct dump_dir *dd = NULL;
|
||
|
+ struct options program_options[] = {
|
||
|
+ OPT__VERBOSE(&g_verbose),
|
||
|
+ OPT__DUMP_DIR(&dump_dir_path),
|
||
|
+ OPT_STRING('u', "url", &arg_server_url, "URL", _("Specify server URL")),
|
||
|
+ OPT_BOOL('k', "insecure", &insecure,
|
||
|
+ _("Allow insecure connection to ureport server")),
|
||
|
+ OPT_STRING('t', "auth", &client_auth, "SOURCE", _("Use client authentication")),
|
||
|
+ OPT_LIST('i', "auth_items", &auth_items, "AUTH_ITEMS", _("Additional files included in 'auth' key")),
|
||
|
+ OPT_STRING('c', NULL, &conf_file, "FILE", _("Configuration file")),
|
||
|
+ OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
|
||
|
+ _("bthash of uReport to attach (conflicts with -A)")),
|
||
|
+ OPT_BOOL('A', "attach-rt", &ureport_hash_from_rt,
|
||
|
+ _("attach to a bthash from reported_to (conflicts with -a)")),
|
||
|
+ OPT_STRING('e', "email", &email_address, "EMAIL",
|
||
|
+ _("contact e-mail address (requires -a|-A, conflicts with -E)")),
|
||
|
+ OPT_BOOL('E', "email-env", &email_address_from_env,
|
||
|
+ _("contact e-mail address from environment or configuration file (requires -a|-A, conflicts with -e)")),
|
||
|
+ OPT_INTEGER('b', "bug-id", &rhbz_bug,
|
||
|
+ _("attach RHBZ bug (requires -a|-A, conflicts with -B)")),
|
||
|
+ OPT_BOOL('B', "bug-id-rt", &rhbz_bug_from_rt,
|
||
|
+ _("attach last RHBZ bug from reported_to (requires -a|-A, conflicts with -b)")),
|
||
|
+ OPT_END(),
|
||
|
+ };
|
||
|
+
|
||
|
+ const char *program_usage_string = _(
|
||
|
+ "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
|
||
|
+ "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-i AUTH_ITEMS]\\\n"
|
||
|
+ " [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
|
||
|
+ "\n"
|
||
|
+ "Upload micro report or add an attachment to a micro report\n"
|
||
|
+ "\n"
|
||
|
+ "Reads the default configuration from "CONF_FILE_PATH
|
||
|
+ );
|
||
|
+
|
||
|
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
|
||
|
+
|
||
|
+ map_string_t *settings = new_map_string();
|
||
|
+ load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);
|
||
|
+
|
||
|
+ load_ureport_server_config(&config, settings);
|
||
|
+
|
||
|
+ if (opts & OPT_u)
|
||
|
+ config.ur_url = arg_server_url;
|
||
|
+ if (opts & OPT_k)
|
||
|
+ config.ur_ssl_verify = !insecure;
|
||
|
+ if (opts & OPT_t)
|
||
|
+ parse_client_auth_paths(&config, client_auth);
|
||
|
+ if (opts & OPT_i)
|
||
|
+ {
|
||
|
+ g_list_free_full(config.ur_prefs.urp_auth_items, free);
|
||
|
+ config.ur_prefs.urp_auth_items = auth_items;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!config.ur_url)
|
||
|
+ error_msg_and_die("You need to specify server URL");
|
||
|
+
|
||
|
+ post_state_t *post_state = NULL;
|
||
|
+
|
||
|
+ if (ureport_hash && ureport_hash_from_rt)
|
||
|
+ error_msg_and_die("You need to pass either -a bthash or -A");
|
||
|
+
|
||
|
+ if (rhbz_bug >= 0 && rhbz_bug_from_rt)
|
||
|
+ error_msg_and_die("You need to pass either -b bug-id or -B");
|
||
|
+
|
||
|
+ if (email_address && email_address_from_env)
|
||
|
+ error_msg_and_die("You need to pass either -e bthash or -E");
|
||
|
+
|
||
|
+ if (ureport_hash_from_rt || rhbz_bug_from_rt)
|
||
|
+ {
|
||
|
+ dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
|
||
|
+ if (!dd)
|
||
|
+ xfunc_die();
|
||
|
+
|
||
|
+ if (ureport_hash_from_rt)
|
||
|
+ {
|
||
|
+ report_result_t *ureport_result = find_in_reported_to(dd, "uReport");
|
||
|
+
|
||
|
+ if (!ureport_result || !ureport_result->bthash)
|
||
|
+ error_msg_and_die(_("This problem does not have an uReport assigned."));
|
||
|
+
|
||
|
+ /* sorry, this will be leaked */
|
||
|
+ ureport_hash = xstrdup(ureport_result->bthash);
|
||
|
+
|
||
|
+ free_report_result(ureport_result);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (rhbz_bug_from_rt)
|
||
|
+ {
|
||
|
+ report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");
|
||
|
+
|
||
|
+ if (!bz_result || !bz_result->url)
|
||
|
+ error_msg_and_die(_("This problem has not been reported to Bugzilla."));
|
||
|
+
|
||
|
+ char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
|
||
|
+ if (!bugid_ptr)
|
||
|
+ error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
|
||
|
+ bugid_ptr += strlen("show_bug.cgi?id=");
|
||
|
+
|
||
|
+ /* we're just reading int, sscanf works fine */
|
||
|
+ if (sscanf(bugid_ptr, "%d", &rhbz_bug) != 1)
|
||
|
+ error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);
|
||
|
+
|
||
|
+ free_report_result(bz_result);
|
||
|
+ }
|
||
|
+
|
||
|
+ dd_close(dd);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (email_address_from_env)
|
||
|
+ {
|
||
|
+ VALUE_FROM_CONF("ContactEmail", email_address, (const char *));
|
||
|
+
|
||
|
+ if (!email_address)
|
||
|
+ error_msg_and_die(_("Neither environment variable 'uReport_ContactEmail' nor configuration option 'ContactEmail' is set"));
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ureport_hash)
|
||
|
+ {
|
||
|
+ if (rhbz_bug < 0 && !email_address)
|
||
|
+ error_msg_and_die(_("You need to specify bug ID, contact email or both"));
|
||
|
+
|
||
|
+ if (rhbz_bug >= 0)
|
||
|
+ {
|
||
|
+ if (perform_attach(&config, ureport_hash, (attach_handler)wrp_ureport_attach_rhbz, (void *)&rhbz_bug))
|
||
|
+ goto finalize;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (email_address)
|
||
|
+ {
|
||
|
+ if (perform_attach(&config, ureport_hash, (attach_handler)ureport_attach_email, (void *)email_address))
|
||
|
+ goto finalize;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = 0;
|
||
|
+ goto finalize;
|
||
|
+ }
|
||
|
+ if (!ureport_hash && (rhbz_bug >= 0 || email_address))
|
||
|
+ error_msg_and_die(_("You need to specify bthash of the uReport to attach."));
|
||
|
+
|
||
|
+ /* -b, -a nor -r were specified - upload uReport from dump_dir */
|
||
|
+ const char *server_url = config.ur_url;
|
||
|
+ char *dest_url = concat_path_file(config.ur_url, REPORT_URL_SFX);
|
||
|
+ config.ur_url = dest_url;
|
||
|
+
|
||
|
+ char *json_ureport = ureport_from_dump_dir_ext(dump_dir_path, &(config.ur_prefs));
|
||
|
+ if (!json_ureport)
|
||
|
+ {
|
||
|
+ error_msg(_("Not uploading an empty uReport"));
|
||
|
+ goto format_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ post_state = ureport_post(json_ureport, &config);
|
||
|
+ free(json_ureport);
|
||
|
+
|
||
|
+ if (!post_state)
|
||
|
+ {
|
||
|
+ error_msg(_("Failed on submitting the problem"));
|
||
|
+ goto format_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ struct ureport_server_response *response = get_server_response(post_state, &config);
|
||
|
+
|
||
|
+ if (!response)
|
||
|
+ goto format_err;
|
||
|
+
|
||
|
+ if (!response->is_error)
|
||
|
+ {
|
||
|
+ log_notice("is known: %s", response->value);
|
||
|
+ ret = 0; /* "success" */
|
||
|
+
|
||
|
+ dd = dd_opendir(dump_dir_path, /* flags */ 0);
|
||
|
+ if (!dd)
|
||
|
+ xfunc_die();
|
||
|
+
|
||
|
+ if (response->bthash)
|
||
|
+ {
|
||
|
+ char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
|
||
|
+ add_reported_to(dd, msg);
|
||
|
+ free(msg);
|
||
|
+
|
||
|
+ char *bthash_url = concat_path_file(server_url, BTHASH_URL_SFX);
|
||
|
+ msg = xasprintf("ABRT Server: URL=%s%s", bthash_url, response->bthash);
|
||
|
+ add_reported_to(dd, msg);
|
||
|
+ free(msg);
|
||
|
+ free(bthash_url);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (response->reported_to_list)
|
||
|
+ {
|
||
|
+ for (GList *e = response->reported_to_list; e; e = g_list_next(e))
|
||
|
+ add_reported_to(dd, e->data);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (response->solution)
|
||
|
+ dd_save_text(dd, FILENAME_NOT_REPORTABLE, response->solution);
|
||
|
+
|
||
|
+ dd_close(dd);
|
||
|
+
|
||
|
+ /* If a reported problem is not known then emit NEEDMORE */
|
||
|
+ if (strcmp("true", response->value) == 0)
|
||
|
+ {
|
||
|
+ log(_("This problem has already been reported."));
|
||
|
+ if (response->message)
|
||
|
+ log(response->message);
|
||
|
+
|
||
|
+ ret = EXIT_STOP_EVENT_RUN;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ error_msg(_("Server responded with an error: '%s'"), response->value);
|
||
|
+ }
|
||
|
+
|
||
|
+ free_ureport_server_response(response);
|
||
|
+
|
||
|
+format_err:
|
||
|
+ free_post_state(post_state);
|
||
|
+ free(dest_url);
|
||
|
+
|
||
|
+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);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c
|
||
|
deleted file mode 100644
|
||
|
index 9c69cad..0000000
|
||
|
--- a/src/plugins/ureport.c
|
||
|
+++ /dev/null
|
||
|
@@ -1,777 +0,0 @@
|
||
|
-/*
|
||
|
- Copyright (C) 2012 ABRT Team
|
||
|
- Copyright (C) 2012 RedHat inc.
|
||
|
-
|
||
|
- This program is free software; you can redistribute it and/or modify
|
||
|
- it under the terms of the GNU General Public License as published by
|
||
|
- the Free Software Foundation; either version 2 of the License, or
|
||
|
- (at your option) any later version.
|
||
|
-
|
||
|
- This program is distributed in the hope that it will be useful,
|
||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
- GNU General Public License for more details.
|
||
|
-
|
||
|
- You should have received a copy of the GNU General Public License along
|
||
|
- with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
-*/
|
||
|
-
|
||
|
-#include <json/json.h>
|
||
|
-#include "internal_libreport.h"
|
||
|
-#include "ureport.h"
|
||
|
-#include "libreport_curl.h"
|
||
|
-
|
||
|
-#define CONF_FILE_PATH PLUGINS_CONF_DIR"/ureport.conf"
|
||
|
-
|
||
|
-#define REPORT_URL_SFX "reports/new/"
|
||
|
-#define ATTACH_URL_SFX "reports/attach/"
|
||
|
-#define BTHASH_URL_SFX "reports/bthash/"
|
||
|
-
|
||
|
-#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)
|
||
|
-
|
||
|
-static char *puppet_config_print(const char *key)
|
||
|
-{
|
||
|
- char *command = xasprintf("puppet config print %s", key);
|
||
|
- char *result = run_in_shell_and_save_output(0, command, NULL, NULL);
|
||
|
- free(command);
|
||
|
-
|
||
|
- /* run_in_shell_and_save_output always returns non-NULL */
|
||
|
- if (result[0] != '/')
|
||
|
- goto error;
|
||
|
-
|
||
|
- char *newline = strchrnul(result, '\n');
|
||
|
- if (!newline)
|
||
|
- goto error;
|
||
|
-
|
||
|
- *newline = '\0';
|
||
|
- return result;
|
||
|
-error:
|
||
|
- free(result);
|
||
|
- error_msg_and_die("Unable to determine puppet %s path (puppet not installed?)", key);
|
||
|
-}
|
||
|
-
|
||
|
-static void parse_client_auth_paths(struct ureport_server_config *config, const char *client_auth)
|
||
|
-{
|
||
|
- if (client_auth == NULL)
|
||
|
- return;
|
||
|
-
|
||
|
- if (strcmp(client_auth, "") == 0)
|
||
|
- {
|
||
|
- config->ur_client_cert = NULL;
|
||
|
- config->ur_client_key = NULL;
|
||
|
- log_notice("Not using client authentication");
|
||
|
- }
|
||
|
- else if (strcmp(client_auth, "rhsm") == 0)
|
||
|
- {
|
||
|
- 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");
|
||
|
- config->ur_client_key = puppet_config_print("hostprivkey");
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- char *scratch = xstrdup(client_auth);
|
||
|
- 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");
|
||
|
- }
|
||
|
-
|
||
|
- if (config->ur_client_cert && config->ur_client_key)
|
||
|
- {
|
||
|
- log_notice("Using client certificate: %s", config->ur_client_cert);
|
||
|
- log_notice("Using client private key: %s", config->ur_client_key);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * Loads uReport configuration from various sources.
|
||
|
- *
|
||
|
- * Replaces a value of an already configured option only if the
|
||
|
- * option was found in a configuration source.
|
||
|
- *
|
||
|
- * @param config a server configuration to be populated
|
||
|
- */
|
||
|
-static void load_ureport_server_config(struct ureport_server_config *config, map_string_t *settings)
|
||
|
-{
|
||
|
- VALUE_FROM_CONF("URL", config->ur_url, (const char *));
|
||
|
- VALUE_FROM_CONF("SSLVerify", config->ur_ssl_verify, string_to_bool);
|
||
|
-
|
||
|
- bool include_auth = false;
|
||
|
- VALUE_FROM_CONF("IncludeAuthData", include_auth, string_to_bool);
|
||
|
-
|
||
|
- if (include_auth)
|
||
|
- {
|
||
|
- const char *auth_items = NULL;
|
||
|
- VALUE_FROM_CONF("AuthDataItems", auth_items, (const char *));
|
||
|
- config->ur_prefs.urp_auth_items = parse_list(auth_items);
|
||
|
-
|
||
|
- if (config->ur_prefs.urp_auth_items == NULL)
|
||
|
- log_warning("IncludeAuthData set to 'yes' but AuthDataItems is empty.");
|
||
|
- }
|
||
|
-
|
||
|
- const char *client_auth = NULL;
|
||
|
- VALUE_FROM_CONF("SSLClientAuth", client_auth, (const char *));
|
||
|
- parse_client_auth_paths(config, client_auth);
|
||
|
-}
|
||
|
-
|
||
|
-struct ureport_server_response {
|
||
|
- bool is_error;
|
||
|
- char *value;
|
||
|
- char *message;
|
||
|
- char *bthash;
|
||
|
- GList *reported_to_list;
|
||
|
- char *solution;
|
||
|
-};
|
||
|
-
|
||
|
-void free_ureport_server_response(struct ureport_server_response *resp)
|
||
|
-{
|
||
|
- if (!resp)
|
||
|
- return;
|
||
|
-
|
||
|
- free(resp->solution);
|
||
|
- g_list_free_full(resp->reported_to_list, g_free);
|
||
|
- free(resp->bthash);
|
||
|
- free(resp->message);
|
||
|
- free(resp->value);
|
||
|
- free(resp);
|
||
|
-}
|
||
|
-
|
||
|
-static char *parse_solution_from_json_list(struct json_object *list, GList **reported_to)
|
||
|
-{
|
||
|
- json_object *list_elem, *struct_elem;
|
||
|
- const char *cause, *note, *url;
|
||
|
- struct strbuf *solution_buf = strbuf_new();
|
||
|
-
|
||
|
- const unsigned length = json_object_array_length(list);
|
||
|
-
|
||
|
- const char *one_format = _("Your problem seems to be caused by %s\n\n%s\n");
|
||
|
- if (length > 1)
|
||
|
- {
|
||
|
- strbuf_append_str(solution_buf, _("Your problem seems to be caused by one of the following:\n"));
|
||
|
- one_format = "\n* %s\n\n%s\n";
|
||
|
- }
|
||
|
-
|
||
|
- bool empty = true;
|
||
|
- for (unsigned i = 0; i < length; ++i)
|
||
|
- {
|
||
|
- list_elem = json_object_array_get_idx(list, i);
|
||
|
- if (!list_elem)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "cause", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- cause = json_object_get_string(struct_elem);
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "note", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- note = json_object_get_string(struct_elem);
|
||
|
- if (!note)
|
||
|
- continue;
|
||
|
-
|
||
|
- empty = false;
|
||
|
- strbuf_append_strf(solution_buf, one_format, cause, note);
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "url", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- url = json_object_get_string(struct_elem);
|
||
|
- if (url)
|
||
|
- {
|
||
|
- char *reported_to_line = xasprintf("%s: URL=%s", cause, url);
|
||
|
- *reported_to = g_list_append(*reported_to, reported_to_line);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- if (empty)
|
||
|
- {
|
||
|
- strbuf_free(solution_buf);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- return strbuf_free_nobuf(solution_buf);
|
||
|
-}
|
||
|
-
|
||
|
-/* reported_to json element should be a list of structures
|
||
|
-{ "reporter": "Bugzilla",
|
||
|
- "type": "url",
|
||
|
- "value": "https://bugzilla.redhat.com/show_bug.cgi?id=XYZ" } */
|
||
|
-static GList *parse_reported_to_from_json_list(struct json_object *list)
|
||
|
-{
|
||
|
- int i;
|
||
|
- json_object *list_elem, *struct_elem;
|
||
|
- const char *reporter, *value, *type;
|
||
|
- char *reported_to_line, *prefix;
|
||
|
- GList *result = NULL;
|
||
|
-
|
||
|
- for (i = 0; i < json_object_array_length(list); ++i)
|
||
|
- {
|
||
|
- prefix = NULL;
|
||
|
- list_elem = json_object_array_get_idx(list, i);
|
||
|
- if (!list_elem)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "reporter", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- reporter = json_object_get_string(struct_elem);
|
||
|
- if (!reporter)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "value", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- value = json_object_get_string(struct_elem);
|
||
|
- if (!value)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!json_object_object_get_ex(list_elem, "type", &struct_elem))
|
||
|
- continue;
|
||
|
-
|
||
|
- type = json_object_get_string(struct_elem);
|
||
|
- if (type)
|
||
|
- {
|
||
|
- if (strcasecmp("url", type) == 0)
|
||
|
- prefix = xstrdup("URL=");
|
||
|
- else if (strcasecmp("bthash", type) == 0)
|
||
|
- prefix = xstrdup("BTHASH=");
|
||
|
- }
|
||
|
-
|
||
|
- if (!prefix)
|
||
|
- prefix = xstrdup("");
|
||
|
-
|
||
|
- reported_to_line = xasprintf("%s: %s%s", reporter, prefix, value);
|
||
|
- free(prefix);
|
||
|
-
|
||
|
- result = g_list_append(result, reported_to_line);
|
||
|
- }
|
||
|
-
|
||
|
- return result;
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * Reponse samples:
|
||
|
- * {"error":"field 'foo' is required"}
|
||
|
- * {"response":"true"}
|
||
|
- * {"response":"false"}
|
||
|
- */
|
||
|
-static struct ureport_server_response *ureport_server_parse_json(json_object *json)
|
||
|
-{
|
||
|
- json_object *obj = NULL;
|
||
|
- if (json_object_object_get_ex(json, "error", &obj))
|
||
|
- {
|
||
|
- struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
|
||
|
- out_response->is_error = true;
|
||
|
- /*
|
||
|
- * Used to use json_object_to_json_string(obj), but it returns
|
||
|
- * the string in quote marks (") - IOW, json-formatted string.
|
||
|
- */
|
||
|
- out_response->value = xstrdup(json_object_get_string(obj));
|
||
|
- return out_response;
|
||
|
- }
|
||
|
-
|
||
|
- if (json_object_object_get_ex(json, "result", &obj))
|
||
|
- {
|
||
|
- struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
|
||
|
- out_response->value = xstrdup(json_object_get_string(obj));
|
||
|
-
|
||
|
- json_object *message = NULL;
|
||
|
- if (json_object_object_get_ex(json, "message", &message))
|
||
|
- out_response->message = xstrdup(json_object_get_string(message));
|
||
|
-
|
||
|
- json_object *bthash = NULL;
|
||
|
- if (json_object_object_get_ex(json, "bthash", &bthash))
|
||
|
- out_response->bthash = xstrdup(json_object_get_string(bthash));
|
||
|
-
|
||
|
- json_object *reported_to_list = NULL;
|
||
|
- if (json_object_object_get_ex(json, "reported_to", &reported_to_list))
|
||
|
- out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
|
||
|
-
|
||
|
- json_object *solutions = NULL;
|
||
|
- if (json_object_object_get_ex(json, "solutions", &solutions))
|
||
|
- out_response->solution = parse_solution_from_json_list(solutions, &(out_response->reported_to_list));
|
||
|
-
|
||
|
- return out_response;
|
||
|
- }
|
||
|
-
|
||
|
- return NULL;
|
||
|
-}
|
||
|
-
|
||
|
-static struct ureport_server_response *get_server_response(post_state_t *post_state, struct ureport_server_config *config)
|
||
|
-{
|
||
|
- /* Previously, the condition here was (post_state->errmsg[0] != '\0')
|
||
|
- * however when the server asks for optional client authentication and we do not have the certificates,
|
||
|
- * then post_state->errmsg contains "NSS: client certificate not found (nickname not specified)" even though
|
||
|
- * the request succeeded.
|
||
|
- */
|
||
|
- if (post_state->curl_result != CURLE_OK)
|
||
|
- {
|
||
|
- error_msg(_("Failed to upload uReport to the server '%s' with curl: %s"), config->ur_url, post_state->errmsg);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (post_state->http_resp_code == 404)
|
||
|
- {
|
||
|
- error_msg(_("The URL '%s' does not exist (got error 404 from server)"), config->ur_url);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (post_state->http_resp_code == 500)
|
||
|
- {
|
||
|
- error_msg(_("The server at '%s' encountered an internal error (got error 500)"), config->ur_url);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (post_state->http_resp_code == 503)
|
||
|
- {
|
||
|
- error_msg(_("The server at '%s' currently can't handle the request (got error 503)"), config->ur_url);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (post_state->http_resp_code != 202
|
||
|
- && post_state->http_resp_code != 400
|
||
|
- && post_state->http_resp_code != 413)
|
||
|
- {
|
||
|
- /* can't print better error message */
|
||
|
- error_msg(_("Unexpected HTTP response from '%s': %d"), config->ur_url, post_state->http_resp_code);
|
||
|
- log_notice("%s", post_state->body);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- json_object *const json = json_tokener_parse(post_state->body);
|
||
|
-
|
||
|
- if (is_error(json))
|
||
|
- {
|
||
|
- error_msg(_("Unable to parse response from ureport server at '%s'"), config->ur_url);
|
||
|
- log_notice("%s", post_state->body);
|
||
|
- json_object_put(json);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- struct ureport_server_response *response = ureport_server_parse_json(json);
|
||
|
- json_object_put(json);
|
||
|
-
|
||
|
- if (!response)
|
||
|
- error_msg(_("The response from '%s' has invalid format"), config->ur_url);
|
||
|
- else if ((post_state->http_resp_code == 202 && response->is_error)
|
||
|
- || (post_state->http_resp_code != 202 && !response->is_error))
|
||
|
- {
|
||
|
- /* HTTP CODE 202 means that call was successful but the response */
|
||
|
- /* has an error message */
|
||
|
- error_msg(_("Type mismatch has been detected in the response from '%s'"), config->ur_url);
|
||
|
- }
|
||
|
-
|
||
|
- return response;
|
||
|
-}
|
||
|
-
|
||
|
-typedef post_state_t *(*attach_handler)(const char *, void *, struct ureport_server_config *);
|
||
|
-
|
||
|
-static post_state_t *wrp_ureport_attach_rhbz(const char *ureport_hash, int *rhbz_bug,
|
||
|
- struct ureport_server_config *config)
|
||
|
-{
|
||
|
- return ureport_attach_rhbz(ureport_hash, *rhbz_bug, config);
|
||
|
-}
|
||
|
-
|
||
|
-static bool perform_attach(struct ureport_server_config *config, const char *ureport_hash,
|
||
|
- attach_handler handler, void *args)
|
||
|
-{
|
||
|
- char *dest_url = concat_path_file(config->ur_url, ATTACH_URL_SFX);
|
||
|
- const char *old_url = config->ur_url;
|
||
|
- config->ur_url = dest_url;
|
||
|
- post_state_t *post_state = handler(ureport_hash, args, config);
|
||
|
- config->ur_url = old_url;
|
||
|
- free(dest_url);
|
||
|
-
|
||
|
- struct ureport_server_response *resp = get_server_response(post_state, config);
|
||
|
- free_post_state(post_state);
|
||
|
- /* don't use str_bo_bool() because we require "true" string */
|
||
|
- const int result = !resp || resp->is_error || strcmp(resp->value,"true") != 0;
|
||
|
-
|
||
|
- if (resp && resp->is_error)
|
||
|
- {
|
||
|
- error_msg(_("The server at '%s' responded with an error: '%s'"), config->ur_url, resp->value);
|
||
|
- }
|
||
|
-
|
||
|
- free_ureport_server_response(resp);
|
||
|
-
|
||
|
- return result;
|
||
|
-}
|
||
|
-
|
||
|
-int main(int argc, char **argv)
|
||
|
-{
|
||
|
- setlocale(LC_ALL, "");
|
||
|
-#if ENABLE_NLS
|
||
|
- bindtextdomain(PACKAGE, LOCALEDIR);
|
||
|
- textdomain(PACKAGE);
|
||
|
-#endif
|
||
|
-
|
||
|
- abrt_init(argv);
|
||
|
-
|
||
|
- struct ureport_server_config config = {
|
||
|
- .ur_url = NULL,
|
||
|
- .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,
|
||
|
- OPT_u = 1 << 2,
|
||
|
- OPT_k = 1 << 3,
|
||
|
- OPT_t = 1 << 4,
|
||
|
- OPT_i = 1 << 5,
|
||
|
- };
|
||
|
-
|
||
|
- int ret = 1; /* "failure" (for now) */
|
||
|
- bool insecure = !config.ur_ssl_verify;
|
||
|
- const char *conf_file = CONF_FILE_PATH;
|
||
|
- const char *arg_server_url = NULL;
|
||
|
- const char *client_auth = NULL;
|
||
|
- GList *auth_items = NULL;
|
||
|
- const char *dump_dir_path = ".";
|
||
|
- const char *ureport_hash = NULL;
|
||
|
- bool ureport_hash_from_rt = false;
|
||
|
- int rhbz_bug = -1;
|
||
|
- bool rhbz_bug_from_rt = false;
|
||
|
- const char *email_address = NULL;
|
||
|
- bool email_address_from_env = false;
|
||
|
- struct dump_dir *dd = NULL;
|
||
|
- struct options program_options[] = {
|
||
|
- OPT__VERBOSE(&g_verbose),
|
||
|
- OPT__DUMP_DIR(&dump_dir_path),
|
||
|
- OPT_STRING('u', "url", &arg_server_url, "URL", _("Specify server URL")),
|
||
|
- OPT_BOOL('k', "insecure", &insecure,
|
||
|
- _("Allow insecure connection to ureport server")),
|
||
|
- OPT_STRING('t', "auth", &client_auth, "SOURCE", _("Use client authentication")),
|
||
|
- OPT_LIST('i', "auth_items", &auth_items, "AUTH_ITEMS", _("Additional files included in 'auth' key")),
|
||
|
- OPT_STRING('c', NULL, &conf_file, "FILE", _("Configuration file")),
|
||
|
- OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
|
||
|
- _("bthash of uReport to attach (conflicts with -A)")),
|
||
|
- OPT_BOOL('A', "attach-rt", &ureport_hash_from_rt,
|
||
|
- _("attach to a bthash from reported_to (conflicts with -a)")),
|
||
|
- OPT_STRING('e', "email", &email_address, "EMAIL",
|
||
|
- _("contact e-mail address (requires -a|-A, conflicts with -E)")),
|
||
|
- OPT_BOOL('E', "email-env", &email_address_from_env,
|
||
|
- _("contact e-mail address from environment or configuration file (requires -a|-A, conflicts with -e)")),
|
||
|
- OPT_INTEGER('b', "bug-id", &rhbz_bug,
|
||
|
- _("attach RHBZ bug (requires -a|-A, conflicts with -B)")),
|
||
|
- OPT_BOOL('B', "bug-id-rt", &rhbz_bug_from_rt,
|
||
|
- _("attach last RHBZ bug from reported_to (requires -a|-A, conflicts with -b)")),
|
||
|
- OPT_END(),
|
||
|
- };
|
||
|
-
|
||
|
- const char *program_usage_string = _(
|
||
|
- "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
|
||
|
- "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-i AUTH_ITEMS]\\\n"
|
||
|
- " [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
|
||
|
- "\n"
|
||
|
- "Upload micro report or add an attachment to a micro report\n"
|
||
|
- "\n"
|
||
|
- "Reads the default configuration from "CONF_FILE_PATH
|
||
|
- );
|
||
|
-
|
||
|
- unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
|
||
|
-
|
||
|
- map_string_t *settings = new_map_string();
|
||
|
- load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);
|
||
|
-
|
||
|
- load_ureport_server_config(&config, settings);
|
||
|
-
|
||
|
- if (opts & OPT_u)
|
||
|
- config.ur_url = arg_server_url;
|
||
|
- if (opts & OPT_k)
|
||
|
- config.ur_ssl_verify = !insecure;
|
||
|
- if (opts & OPT_t)
|
||
|
- parse_client_auth_paths(&config, client_auth);
|
||
|
- if (opts & OPT_i)
|
||
|
- {
|
||
|
- g_list_free_full(config.ur_prefs.urp_auth_items, free);
|
||
|
- config.ur_prefs.urp_auth_items = auth_items;
|
||
|
- }
|
||
|
-
|
||
|
- if (!config.ur_url)
|
||
|
- error_msg_and_die("You need to specify server URL");
|
||
|
-
|
||
|
- post_state_t *post_state = NULL;
|
||
|
-
|
||
|
- if (ureport_hash && ureport_hash_from_rt)
|
||
|
- error_msg_and_die("You need to pass either -a bthash or -A");
|
||
|
-
|
||
|
- if (rhbz_bug >= 0 && rhbz_bug_from_rt)
|
||
|
- error_msg_and_die("You need to pass either -b bug-id or -B");
|
||
|
-
|
||
|
- if (email_address && email_address_from_env)
|
||
|
- error_msg_and_die("You need to pass either -e bthash or -E");
|
||
|
-
|
||
|
- if (ureport_hash_from_rt || rhbz_bug_from_rt)
|
||
|
- {
|
||
|
- dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
|
||
|
- if (!dd)
|
||
|
- xfunc_die();
|
||
|
-
|
||
|
- if (ureport_hash_from_rt)
|
||
|
- {
|
||
|
- report_result_t *ureport_result = find_in_reported_to(dd, "uReport");
|
||
|
-
|
||
|
- if (!ureport_result || !ureport_result->bthash)
|
||
|
- error_msg_and_die(_("This problem does not have an uReport assigned."));
|
||
|
-
|
||
|
- /* sorry, this will be leaked */
|
||
|
- ureport_hash = xstrdup(ureport_result->bthash);
|
||
|
-
|
||
|
- free_report_result(ureport_result);
|
||
|
- }
|
||
|
-
|
||
|
- if (rhbz_bug_from_rt)
|
||
|
- {
|
||
|
- report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");
|
||
|
-
|
||
|
- if (!bz_result || !bz_result->url)
|
||
|
- error_msg_and_die(_("This problem has not been reported to Bugzilla."));
|
||
|
-
|
||
|
- char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
|
||
|
- if (!bugid_ptr)
|
||
|
- error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
|
||
|
- bugid_ptr += strlen("show_bug.cgi?id=");
|
||
|
-
|
||
|
- /* we're just reading int, sscanf works fine */
|
||
|
- if (sscanf(bugid_ptr, "%d", &rhbz_bug) != 1)
|
||
|
- error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);
|
||
|
-
|
||
|
- free_report_result(bz_result);
|
||
|
- }
|
||
|
-
|
||
|
- dd_close(dd);
|
||
|
- }
|
||
|
-
|
||
|
- if (email_address_from_env)
|
||
|
- {
|
||
|
- VALUE_FROM_CONF("ContactEmail", email_address, (const char *));
|
||
|
-
|
||
|
- if (!email_address)
|
||
|
- error_msg_and_die(_("Neither environment variable 'uReport_ContactEmail' nor configuration option 'ContactEmail' is set"));
|
||
|
- }
|
||
|
-
|
||
|
- if (ureport_hash)
|
||
|
- {
|
||
|
- if (rhbz_bug < 0 && !email_address)
|
||
|
- error_msg_and_die(_("You need to specify bug ID, contact email or both"));
|
||
|
-
|
||
|
- if (rhbz_bug >= 0)
|
||
|
- {
|
||
|
- if (perform_attach(&config, ureport_hash, (attach_handler)wrp_ureport_attach_rhbz, (void *)&rhbz_bug))
|
||
|
- goto finalize;
|
||
|
- }
|
||
|
-
|
||
|
- if (email_address)
|
||
|
- {
|
||
|
- if (perform_attach(&config, ureport_hash, (attach_handler)ureport_attach_email, (void *)email_address))
|
||
|
- goto finalize;
|
||
|
- }
|
||
|
-
|
||
|
- ret = 0;
|
||
|
- goto finalize;
|
||
|
- }
|
||
|
- if (!ureport_hash && (rhbz_bug >= 0 || email_address))
|
||
|
- error_msg_and_die(_("You need to specify bthash of the uReport to attach."));
|
||
|
-
|
||
|
- /* -b, -a nor -r were specified - upload uReport from dump_dir */
|
||
|
- const char *server_url = config.ur_url;
|
||
|
- char *dest_url = concat_path_file(config.ur_url, REPORT_URL_SFX);
|
||
|
- config.ur_url = dest_url;
|
||
|
-
|
||
|
- char *json_ureport = ureport_from_dump_dir_ext(dump_dir_path, &(config.ur_prefs));
|
||
|
- if (!json_ureport)
|
||
|
- {
|
||
|
- error_msg(_("Not uploading an empty uReport"));
|
||
|
- goto format_err;
|
||
|
- }
|
||
|
-
|
||
|
- post_state = post_ureport(json_ureport, &config);
|
||
|
- free(json_ureport);
|
||
|
-
|
||
|
- if (!post_state)
|
||
|
- {
|
||
|
- error_msg(_("Failed on submitting the problem"));
|
||
|
- goto format_err;
|
||
|
- }
|
||
|
-
|
||
|
- struct ureport_server_response *response = get_server_response(post_state, &config);
|
||
|
-
|
||
|
- if (!response)
|
||
|
- goto format_err;
|
||
|
-
|
||
|
- if (!response->is_error)
|
||
|
- {
|
||
|
- log_notice("is known: %s", response->value);
|
||
|
- ret = 0; /* "success" */
|
||
|
-
|
||
|
- dd = dd_opendir(dump_dir_path, /* flags */ 0);
|
||
|
- if (!dd)
|
||
|
- xfunc_die();
|
||
|
-
|
||
|
- if (response->bthash)
|
||
|
- {
|
||
|
- char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
|
||
|
- add_reported_to(dd, msg);
|
||
|
- free(msg);
|
||
|
-
|
||
|
- char *bthash_url = concat_path_file(server_url, BTHASH_URL_SFX);
|
||
|
- msg = xasprintf("ABRT Server: URL=%s%s", bthash_url, response->bthash);
|
||
|
- add_reported_to(dd, msg);
|
||
|
- free(msg);
|
||
|
- free(bthash_url);
|
||
|
- }
|
||
|
-
|
||
|
- if (response->reported_to_list)
|
||
|
- {
|
||
|
- for (GList *e = response->reported_to_list; e; e = g_list_next(e))
|
||
|
- add_reported_to(dd, e->data);
|
||
|
- }
|
||
|
-
|
||
|
- if (response->solution)
|
||
|
- dd_save_text(dd, FILENAME_NOT_REPORTABLE, response->solution);
|
||
|
-
|
||
|
- dd_close(dd);
|
||
|
-
|
||
|
- /* If a reported problem is not known then emit NEEDMORE */
|
||
|
- if (strcmp("true", response->value) == 0)
|
||
|
- {
|
||
|
- log(_("This problem has already been reported."));
|
||
|
- if (response->message)
|
||
|
- log(response->message);
|
||
|
-
|
||
|
- ret = EXIT_STOP_EVENT_RUN;
|
||
|
- }
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- error_msg(_("Server responded with an error: '%s'"), response->value);
|
||
|
- }
|
||
|
-
|
||
|
- free_ureport_server_response(response);
|
||
|
-
|
||
|
-format_err:
|
||
|
- free_post_state(post_state);
|
||
|
- free(dest_url);
|
||
|
-
|
||
|
-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);
|
||
|
-
|
||
|
- return ret;
|
||
|
-}
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|