Signed-off-by: Michal Toman <mto...@redhat.com>
---
 src/plugins/abrt-retrace-client.c | 138 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 131 insertions(+), 7 deletions(-)

diff --git a/src/plugins/abrt-retrace-client.c 
b/src/plugins/abrt-retrace-client.c
index 1712702..8b35dbe 100644
--- a/src/plugins/abrt-retrace-client.c
+++ b/src/plugins/abrt-retrace-client.c
@@ -21,6 +21,7 @@
 #define MAX_FORMATS 16
 #define MAX_RELEASES 32
 #define MAX_DOTS_PER_LINE 80
+#define MIN_EXPLOITABLE_RATING 4
 
 enum
 {
@@ -929,6 +930,93 @@ static void run_backtrace(const char *task_id, const char 
*task_password)
     free(backtrace_text);
 }
 
+/* This is not robust at all but will work for now */
+static int get_exploitable_rating(const char *exploitable_text)
+{
+    const char *colon = strrchr(exploitable_text, ':');
+    int result;
+    if (!colon || sscanf(colon, ": %d", &result) != 1)
+    {
+        VERB1 log_msg("Unable to determine exploitable rating");
+        return -1;
+    }
+
+    VERB1 log_msg("Exploitable rating: %d", result);
+    return result;
+}
+
+/* Caller must free exploitable_text */
+static void exploitable(const char *task_id, const char *task_password,
+                        char **exploitable_text)
+{
+    PRFileDesc *tcp_sock, *ssl_sock;
+    ssl_connect(&cfg, &tcp_sock, &ssl_sock);
+    struct strbuf *http_request = strbuf_new();
+    strbuf_append_strf(http_request,
+                       "GET /%s/exploitable HTTP/1.1\r\n"
+                       "Host: %s\r\n"
+                       "X-Task-Password: %s\r\n"
+                       "Content-Length: 0\r\n"
+                       "Connection: close\r\n"
+                       "%s"
+                       "%s"
+                       "\r\n",
+                       task_id, cfg.url, task_password,
+                       lang.accept_charset,
+                       lang.accept_language
+    );
+
+    PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
+                              /*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
+    if (written == -1)
+    {
+        alert_connection_error(cfg.url);
+        error_msg_and_die(_("Failed to send HTTP header of length %d: NSS 
error %d."),
+                          http_request->len, PR_GetError());
+    }
+    strbuf_free(http_request);
+    char *http_response = tcp_read_response(tcp_sock);
+    char *http_body = http_get_body(http_response);
+    if (!http_body)
+    {
+        alert_server_error(cfg.url);
+        error_msg_and_die(_("Invalid response from server: missing HTTP 
message body."));
+    }
+    if (http_show_headers)
+        http_print_headers(stderr, http_response);
+    int response_code = http_get_response_code(http_response);
+
+    free(http_response);
+    ssl_disconnect(ssl_sock);
+
+    /* 404 = exploitability results not available
+       200 = OK
+       anything else = error */
+    if (response_code == 404)
+        *exploitable_text = NULL;
+    else if (response_code == 200)
+        *exploitable_text = http_body;
+    else
+    {
+        alert_server_error(cfg.url);
+        error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
+                          response_code, http_body);
+    }
+}
+
+static void run_exploitable(const char *task_id, const char *task_password)
+{
+    char *exploitable_text;
+    exploitable(task_id, task_password, &exploitable_text);
+    if (exploitable_text)
+    {
+        printf("%s\n", exploitable_text);
+        free(exploitable_text);
+    }
+    else
+        puts("No exploitability information available.");
+}
+
 static void run_log(const char *task_id, const char *task_password)
 {
     PRFileDesc *tcp_sock, *ssl_sock;
@@ -1026,19 +1114,47 @@ static int run_batch(bool delete_temp_archive)
     {
         char *backtrace_text;
         backtrace(task_id, task_password, &backtrace_text);
+        char *exploitable_text = NULL;
+        if (task_type == TASK_RETRACE)
+        {
+            exploitable(task_id, task_password, &exploitable_text);
+            if (!exploitable_text)
+                VERB1 log_msg("No exploitable data available");
+        }
+
         if (dump_dir_name)
         {
+            struct dump_dir *dd = dd_opendir(dump_dir_name, 0/* flags */);
+            if (!dd)
+            {
+                free(backtrace_text);
+                xfunc_die();
+            }
+
             /* the result of TASK_VMCORE is not backtrace, but kernel log */
-            char *backtrace_path = xasprintf("%s/%s", dump_dir_name,
-                                             task_type == TASK_VMCORE ? 
FILENAME_KERNEL_LOG : FILENAME_BACKTRACE);
-            int backtrace_fd = xopen3(backtrace_path, O_WRONLY | O_CREAT | 
O_TRUNC, DEFAULT_DUMP_DIR_MODE);
-            xwrite(backtrace_fd, backtrace_text, strlen(backtrace_text));
-            close(backtrace_fd);
-            free(backtrace_path);
+            const char *target = task_type == TASK_VMCORE ? 
FILENAME_KERNEL_LOG : FILENAME_BACKTRACE;
+            dd_save_text(dd, target, backtrace_text);
+
+            if (exploitable_text)
+            {
+                int exploitable_rating = 
get_exploitable_rating(exploitable_text);
+                if (exploitable_rating >= MIN_EXPLOITABLE_RATING)
+                    dd_save_text(dd, FILENAME_EXPLOITABLE, exploitable_text);
+                else
+                    VERB1 log_msg("Not saving exploitable data, rating < %d",
+                                  MIN_EXPLOITABLE_RATING);
+            }
+
+            dd_close(dd);
         }
         else
-            printf("%s", backtrace_text);
+        {
+            printf("%s\n", backtrace_text);
+            if (exploitable_text)
+                printf("%s\n", exploitable_text);
+        }
         free(backtrace_text);
+        free(exploitable_text);
     }
     else
     {
@@ -1198,6 +1314,14 @@ int main(int argc, char **argv)
             error_msg_and_die(_("Task password is needed."));
         run_log(task_id, task_password);
     }
+    else if (0 == strcasecmp(operation, "exploitable"))
+    {
+        if (!task_id)
+            error_msg_and_die(_("Task id is needed."));
+        if (!task_password)
+            error_msg_and_die(_("Task password is needed."));
+        run_exploitable(task_id, task_password);
+    }
     else
         error_msg_and_die(_("Unknown operation: %s."), operation);
 
-- 
1.8.3.1

Reply via email to