|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2010 Red Hat, Inc.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
8ea169 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
8ea169 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
#include "https-utils.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define MAX_FORMATS 16
|
|
Packit |
8ea169 |
#define MAX_RELEASES 32
|
|
Packit |
8ea169 |
#define MAX_DOTS_PER_LINE 80
|
|
Packit |
8ea169 |
#define MIN_EXPLOITABLE_RATING 4
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
enum
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
TASK_RETRACE,
|
|
Packit |
8ea169 |
TASK_DEBUG,
|
|
Packit |
8ea169 |
TASK_VMCORE,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static struct language lang;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct retrace_settings
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int running_tasks;
|
|
Packit |
8ea169 |
int max_running_tasks;
|
|
Packit |
8ea169 |
long long max_packed_size;
|
|
Packit |
8ea169 |
long long max_unpacked_size;
|
|
Packit |
8ea169 |
char *supported_formats[MAX_FORMATS];
|
|
Packit |
8ea169 |
char *supported_releases[MAX_RELEASES];
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static const char *dump_dir_name = NULL;
|
|
Packit |
8ea169 |
static const char *coredump = NULL;
|
|
Packit |
8ea169 |
static const char *required_retrace[] = { FILENAME_COREDUMP,
|
|
Packit |
8ea169 |
FILENAME_EXECUTABLE,
|
|
Packit |
8ea169 |
FILENAME_PACKAGE,
|
|
Packit |
8ea169 |
FILENAME_OS_RELEASE,
|
|
Packit |
8ea169 |
NULL };
|
|
Packit |
8ea169 |
static const char *optional_retrace[] = { FILENAME_ROOTDIR,
|
|
Packit |
8ea169 |
FILENAME_OS_RELEASE_IN_ROOTDIR,
|
|
Packit |
8ea169 |
NULL };
|
|
Packit |
8ea169 |
static const char *required_vmcore[] = { FILENAME_VMCORE,
|
|
Packit |
8ea169 |
NULL };
|
|
Packit |
8ea169 |
static unsigned delay = 0;
|
|
Packit |
8ea169 |
static int task_type = TASK_RETRACE;
|
|
Packit |
8ea169 |
static bool http_show_headers;
|
|
Packit |
8ea169 |
static bool no_pkgcheck;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static struct https_cfg cfg =
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
.url = "retrace.fedoraproject.org",
|
|
Packit |
8ea169 |
.port = 443,
|
|
Packit |
8ea169 |
.ssl_allow_insecure = false,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void alert_crash_too_large()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert(_("Retrace server can not be used, because the crash "
|
|
Packit |
8ea169 |
"is too large. Try local retracing."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Add an entry name to the args array if the entry name exists in a
|
|
Packit |
8ea169 |
* problem directory. The entry is added to argindex offset to the array,
|
|
Packit |
8ea169 |
* and the argindex is then increased.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static void args_add_if_exists(const char *args[],
|
|
Packit |
8ea169 |
struct dump_dir *dd,
|
|
Packit |
8ea169 |
const char *name,
|
|
Packit |
8ea169 |
int *argindex)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (dd_exist(dd, name))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
args[*argindex] = name;
|
|
Packit |
8ea169 |
*argindex += 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Create an archive with files required for retrace server and return
|
|
Packit |
8ea169 |
* a file descriptor. Returns -1 if it fails.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static int create_archive(bool unlink_temp)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
return -1;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Open a temporary file. */
|
|
Packit |
8ea169 |
char *filename = xstrdup(LARGE_DATA_TMP_DIR"/abrt-retrace-client-archive-XXXXXX.tar.xz");
|
|
Packit |
8ea169 |
int tempfd = mkstemps(filename, /*suffixlen:*/7);
|
|
Packit |
8ea169 |
if (tempfd == -1)
|
|
Packit |
8ea169 |
perror_msg_and_die(_("Can't create temporary file in "LARGE_DATA_TMP_DIR));
|
|
Packit |
8ea169 |
if (unlink_temp)
|
|
Packit |
8ea169 |
xunlink(filename);
|
|
Packit |
8ea169 |
free(filename);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Run xz:
|
|
Packit |
8ea169 |
* - xz reads input from a pipe
|
|
Packit |
8ea169 |
* - xz writes output to the temporary file.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
const char *xz_args[4];
|
|
Packit |
8ea169 |
xz_args[0] = "xz";
|
|
Packit |
8ea169 |
xz_args[1] = "-2";
|
|
Packit |
8ea169 |
xz_args[2] = "-";
|
|
Packit |
8ea169 |
xz_args[3] = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int tar_xz_pipe[2];
|
|
Packit |
8ea169 |
xpipe(tar_xz_pipe);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
fflush(NULL); /* paranoia */
|
|
Packit |
8ea169 |
pid_t xz_child = vfork();
|
|
Packit |
8ea169 |
if (xz_child == -1)
|
|
Packit |
8ea169 |
perror_msg_and_die("vfork");
|
|
Packit |
8ea169 |
if (xz_child == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
close(tar_xz_pipe[1]);
|
|
Packit |
8ea169 |
xmove_fd(tar_xz_pipe[0], STDIN_FILENO);
|
|
Packit |
8ea169 |
xmove_fd(tempfd, STDOUT_FILENO);
|
|
Packit |
8ea169 |
execvp(xz_args[0], (char * const*)xz_args);
|
|
Packit |
8ea169 |
perror_msg_and_die(_("Can't execute '%s'"), xz_args[0]);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
close(tar_xz_pipe[0]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Run tar, and set output to a pipe with xz waiting on the other
|
|
Packit |
8ea169 |
* end.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
const char *tar_args[10];
|
|
Packit |
8ea169 |
tar_args[0] = "tar";
|
|
Packit |
8ea169 |
tar_args[1] = "cO";
|
|
Packit |
8ea169 |
tar_args[2] = xasprintf("--directory=%s", dump_dir_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char **required_files = task_type == TASK_VMCORE ? required_vmcore : required_retrace;
|
|
Packit |
8ea169 |
int index = 3;
|
|
Packit |
8ea169 |
while (required_files[index - 3])
|
|
Packit |
8ea169 |
args_add_if_exists(tar_args, dd, required_files[index - 3], &index);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (task_type == TASK_RETRACE || task_type == TASK_DEBUG)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
for (i = 0; optional_retrace[i]; ++i)
|
|
Packit |
8ea169 |
args_add_if_exists(tar_args, dd, optional_retrace[i], &index);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
tar_args[index] = NULL;
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
fflush(NULL); /* paranoia */
|
|
Packit |
8ea169 |
pid_t tar_child = vfork();
|
|
Packit |
8ea169 |
if (tar_child == -1)
|
|
Packit |
8ea169 |
perror_msg_and_die("vfork");
|
|
Packit |
8ea169 |
if (tar_child == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
|
|
Packit |
8ea169 |
xmove_fd(tar_xz_pipe[1], STDOUT_FILENO);
|
|
Packit |
8ea169 |
execvp(tar_args[0], (char * const*)tar_args);
|
|
Packit |
8ea169 |
perror_msg_and_die(_("Can't execute '%s'"), tar_args[0]);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free((void*)tar_args[2]);
|
|
Packit |
8ea169 |
close(tar_xz_pipe[1]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Wait for tar and xz to finish successfully */
|
|
Packit |
8ea169 |
int status;
|
|
Packit |
8ea169 |
log_notice("Waiting for tar...");
|
|
Packit |
8ea169 |
safe_waitpid(tar_child, &status, 0);
|
|
Packit |
8ea169 |
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
Packit |
8ea169 |
/* Hopefully, by this time child emitted more meaningful
|
|
Packit |
8ea169 |
* error message. But just in case it didn't:
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
error_msg_and_die(_("Can't create temporary file in "LARGE_DATA_TMP_DIR));
|
|
Packit |
8ea169 |
log_notice("Waiting for xz...");
|
|
Packit |
8ea169 |
safe_waitpid(xz_child, &status, 0);
|
|
Packit |
8ea169 |
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Can't create temporary file in "LARGE_DATA_TMP_DIR));
|
|
Packit |
8ea169 |
log_notice("Done...");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
xlseek(tempfd, 0, SEEK_SET);
|
|
Packit |
8ea169 |
return tempfd;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct retrace_settings *get_settings()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct retrace_settings *settings = xzalloc(sizeof(struct retrace_settings));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /settings HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"\r\n", cfg.url);
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d"),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
if (response_code != 200)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_response);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *headers_end = strstr(http_response, "\r\n\r\n");
|
|
Packit |
8ea169 |
char *c, *row, *value;
|
|
Packit |
8ea169 |
if (!headers_end)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
row = headers_end + strlen("\r\n\r\n");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
do
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* split rows */
|
|
Packit |
8ea169 |
c = strchr(row, '\n');
|
|
Packit |
8ea169 |
if (c)
|
|
Packit |
8ea169 |
*c = '\0';
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* split key and values */
|
|
Packit |
8ea169 |
value = strchr(row, ' ');
|
|
Packit |
8ea169 |
if (!value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
row = c + 1;
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*value = '\0';
|
|
Packit |
8ea169 |
++value;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (0 == strcasecmp("running_tasks", row))
|
|
Packit |
8ea169 |
settings->running_tasks = atoi(value);
|
|
Packit |
8ea169 |
else if (0 == strcasecmp("max_running_tasks", row))
|
|
Packit |
8ea169 |
settings->max_running_tasks = atoi(value);
|
|
Packit |
8ea169 |
else if (0 == strcasecmp("max_packed_size", row))
|
|
Packit |
8ea169 |
settings->max_packed_size = atoll(value) * 1024 * 1024;
|
|
Packit |
8ea169 |
else if (0 == strcasecmp("max_unpacked_size", row))
|
|
Packit |
8ea169 |
settings->max_unpacked_size = atoll(value) * 1024 * 1024;
|
|
Packit |
8ea169 |
else if (0 == strcasecmp("supported_formats", row))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *space;
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_FORMATS - 1 && (space = strchr(value, ' ')); ++i)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
*space = '\0';
|
|
Packit |
8ea169 |
settings->supported_formats[i] = xstrdup(value);
|
|
Packit |
8ea169 |
value = space + 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* last element */
|
|
Packit |
8ea169 |
settings->supported_formats[i] = xstrdup(value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp("supported_releases", row))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *space;
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_RELEASES - 1 && (space = strchr(value, ' ')); ++i)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
*space = '\0';
|
|
Packit |
8ea169 |
settings->supported_releases[i] = xstrdup(value);
|
|
Packit |
8ea169 |
value = space + 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* last element */
|
|
Packit |
8ea169 |
settings->supported_releases[i] = xstrdup(value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* the beginning of the next row */
|
|
Packit |
8ea169 |
row = c + 1;
|
|
Packit |
8ea169 |
} while (c);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return settings;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void free_settings(struct retrace_settings *settings)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!settings)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_FORMATS; ++i)
|
|
Packit |
8ea169 |
free(settings->supported_formats[i]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_RELEASES; ++i)
|
|
Packit |
8ea169 |
free(settings->supported_releases[i]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(settings);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* returns release identifier as dist-ver-arch */
|
|
Packit |
8ea169 |
/* or NULL if unknown */
|
|
Packit |
8ea169 |
static char *get_release_id(map_string_t *osinfo, const char *architecture)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *arch = xstrdup(architecture);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (strcmp("i686", arch) == 0 || strcmp("i586", arch) == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
free(arch);
|
|
Packit |
8ea169 |
arch = xstrdup("i386");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *result = NULL;
|
|
Packit |
8ea169 |
char *release = NULL;
|
|
Packit |
8ea169 |
char *version = NULL;
|
|
Packit |
8ea169 |
parse_osinfo_for_rhts(osinfo, (char **)&release, (char **)&version);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (release == NULL || version == NULL)
|
|
Packit |
8ea169 |
error_msg_and_die("Can't parse OS release name or version");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *space = strchr(version, ' ');
|
|
Packit |
8ea169 |
if (space)
|
|
Packit |
8ea169 |
*space = '\0';
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (strcmp("Fedora", release) == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Because of inconsistency between Fedora's os-release and retrace
|
|
Packit |
8ea169 |
* server.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Adding the reporting fields to Fedora's os-release was a bit
|
|
Packit |
8ea169 |
* frustrating for all participants and fixing it on the retrace server
|
|
Packit |
8ea169 |
* side is neither feasible nor acceptable.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Therefore, we have decided to add the following hack.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
if (strcmp("Rawhide", version) == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Rawhide -> rawhide */
|
|
Packit |
8ea169 |
version[0] = 'r';
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
/* Fedora -> fedora */
|
|
Packit |
8ea169 |
release[0] = 'f';
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (strcmp("Red Hat Enterprise Linux", release) == 0)
|
|
Packit |
8ea169 |
strcpy(release, "rhel");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
result = xasprintf("%s-%s-%s", release, version, arch);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(release);
|
|
Packit |
8ea169 |
free(version);
|
|
Packit |
8ea169 |
free(arch);
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int check_package(const char *nvr, const char *arch, map_string_t *osinfo, char **msg)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *releaseid = get_release_id(osinfo, arch);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /checkpackage HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"X-Package-NVR: %s\r\n"
|
|
Packit |
8ea169 |
"X-Package-Arch: %s\r\n"
|
|
Packit |
8ea169 |
"X-OS-Release: %s\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
cfg.url, nvr, arch, releaseid,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d"),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
/* we are expecting either 302 or 404 */
|
|
Packit |
8ea169 |
if (response_code != 302 && response_code != 404)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (msg)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (response_code == 404)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *os = get_map_string_item_or_empty(osinfo, OSINFO_PRETTY_NAME);
|
|
Packit |
8ea169 |
if (!os)
|
|
Packit |
8ea169 |
os = get_map_string_item_or_empty(osinfo, OSINFO_NAME);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*msg = xasprintf(_("Retrace server is unable to process package "
|
|
Packit |
8ea169 |
"'%s.%s'.\nIs it a part of official '%s' repositories?"),
|
|
Packit |
8ea169 |
nvr, arch, os);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
*msg = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
free(releaseid);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return response_code == 302;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int create(bool delete_temp_archive,
|
|
Packit |
8ea169 |
char **task_id,
|
|
Packit |
8ea169 |
char **task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
puts(_("Querying server settings"));
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct retrace_settings *settings = get_settings();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (settings->running_tasks >= settings->max_running_tasks)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert(_("The server is fully occupied. Try again later."));
|
|
Packit |
8ea169 |
error_msg_and_die(_("The server denied your request."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
long long unpacked_size = 0;
|
|
Packit |
8ea169 |
struct stat file_stat;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* get raw size */
|
|
Packit |
8ea169 |
if (coredump)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
xstat(coredump, &file_stat);
|
|
Packit |
8ea169 |
unpacked_size = (long long)file_stat.st_size;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (dump_dir_name != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags*/ 0);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
xfunc_die(); /* dd_opendir already emitted error message */
|
|
Packit |
8ea169 |
if (dd_exist(dd, FILENAME_VMCORE))
|
|
Packit |
8ea169 |
task_type = TASK_VMCORE;
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *path;
|
|
Packit |
8ea169 |
int i = 0;
|
|
Packit |
8ea169 |
const char **required_files = task_type == TASK_VMCORE ? required_vmcore : required_retrace;
|
|
Packit |
8ea169 |
while (required_files[i])
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
path = concat_path_file(dump_dir_name, required_files[i]);
|
|
Packit |
8ea169 |
xstat(path, &file_stat);
|
|
Packit |
8ea169 |
free(path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!S_ISREG(file_stat.st_mode))
|
|
Packit |
8ea169 |
error_msg_and_die(_("'%s' must be a regular file in "
|
|
Packit |
8ea169 |
"order to use Retrace server."),
|
|
Packit |
8ea169 |
required_files[i]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unpacked_size += (long long)file_stat.st_size;
|
|
Packit |
8ea169 |
++i;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (task_type == TASK_RETRACE || task_type == TASK_DEBUG)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
for (i = 0; optional_retrace[i]; ++i)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
path = concat_path_file(dump_dir_name, optional_retrace[i]);
|
|
Packit |
8ea169 |
if (stat(path, &file_stat) != -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!S_ISREG(file_stat.st_mode))
|
|
Packit |
8ea169 |
error_msg_and_die(_("'%s' must be a regular file in "
|
|
Packit |
8ea169 |
"order to use Retrace server."),
|
|
Packit |
8ea169 |
required_files[i]);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unpacked_size += (long long)file_stat.st_size;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(path);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (unpacked_size > settings->max_unpacked_size)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_crash_too_large();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Leaking size and max_size in hope the memory will be released in
|
|
Packit |
8ea169 |
* error_msg_and_die() */
|
|
Packit |
8ea169 |
gchar *size = g_format_size_full(unpacked_size, G_FORMAT_SIZE_IEC_UNITS);
|
|
Packit |
8ea169 |
gchar *max_size = g_format_size_full(settings->max_unpacked_size, G_FORMAT_SIZE_IEC_UNITS);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
error_msg_and_die(_("The size of your crash is %s, "
|
|
Packit |
8ea169 |
"but the retrace server only accepts "
|
|
Packit |
8ea169 |
"crashes smaller or equal to %s."),
|
|
Packit |
8ea169 |
size, max_size);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (settings->supported_formats)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
bool supported = false;
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_FORMATS && settings->supported_formats[i]; ++i)
|
|
Packit |
8ea169 |
if (strcmp("application/x-xz-compressed-tar", settings->supported_formats[i]) == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
supported = true;
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!supported)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("The server does not support "
|
|
Packit |
8ea169 |
"xz-compressed tarballs."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (task_type != TASK_VMCORE && dump_dir_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
xfunc_die();
|
|
Packit |
8ea169 |
problem_data_t *pd = create_problem_data_from_dump_dir(dd);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *package = problem_data_get_content_or_NULL(pd, FILENAME_PACKAGE);
|
|
Packit |
8ea169 |
char *arch = problem_data_get_content_or_NULL(pd, FILENAME_ARCHITECTURE);
|
|
Packit |
8ea169 |
map_string_t *osinfo = new_map_string();
|
|
Packit |
8ea169 |
problem_data_get_osinfo(pd, osinfo);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* not needed for TASK_VMCORE - the information is kept in the vmcore itself */
|
|
Packit |
8ea169 |
if (settings->supported_releases)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *releaseid = get_release_id(osinfo, arch);
|
|
Packit |
8ea169 |
if (!releaseid)
|
|
Packit |
8ea169 |
error_msg_and_die("Unable to parse release.");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
bool supported = false;
|
|
Packit |
8ea169 |
for (i = 0; i < MAX_RELEASES && settings->supported_releases[i]; ++i)
|
|
Packit |
8ea169 |
if (strcmp(releaseid, settings->supported_releases[i]) == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
supported = true;
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!supported)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *msg = xasprintf(_("The release '%s' is not supported by the"
|
|
Packit |
8ea169 |
" Retrace server."), releaseid);
|
|
Packit |
8ea169 |
alert(msg);
|
|
Packit |
8ea169 |
free(msg);
|
|
Packit |
8ea169 |
error_msg_and_die(_("The server is not able to"
|
|
Packit |
8ea169 |
" handle your request."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(releaseid);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* not relevant for vmcores - it may take a long time to get package from vmcore */
|
|
Packit |
8ea169 |
if (!no_pkgcheck)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *msg;
|
|
Packit |
8ea169 |
int known = check_package(package, arch, osinfo, &msg;;
|
|
Packit |
8ea169 |
if (msg)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert(msg);
|
|
Packit |
8ea169 |
free(msg);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!known)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unknown package sent to Retrace server."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_map_string(osinfo);
|
|
Packit |
8ea169 |
problem_data_free(pd);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
puts(_("Preparing an archive to upload"));
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int tempfd = create_archive(delete_temp_archive);
|
|
Packit |
8ea169 |
if (-1 == tempfd)
|
|
Packit |
8ea169 |
return 1;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Get the file size. */
|
|
Packit |
8ea169 |
fstat(tempfd, &file_stat);
|
|
Packit |
8ea169 |
gchar *human_size = g_format_size_full((long long)file_stat.st_size, G_FORMAT_SIZE_IEC_UNITS);
|
|
Packit |
8ea169 |
if ((long long)file_stat.st_size > settings->max_packed_size)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_crash_too_large();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Leaking human_size and max_size in hope the memory will be released in
|
|
Packit |
8ea169 |
* error_msg_and_die() */
|
|
Packit |
8ea169 |
gchar *max_size = g_format_size_full(settings->max_packed_size, G_FORMAT_SIZE_IEC_UNITS);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
error_msg_and_die(_("The size of your archive is %s, "
|
|
Packit |
8ea169 |
"but the retrace server only accepts "
|
|
Packit |
8ea169 |
"archives smaller or equal to %s."),
|
|
Packit |
8ea169 |
human_size, max_size);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_settings(settings);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int size_mb = file_stat.st_size / (1024 * 1024);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (size_mb > 8) /* 8 MB - should be configurable */
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *question = xasprintf(_("You are going to upload %s. "
|
|
Packit |
8ea169 |
"Continue?"), human_size);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int response = ask_yes_no(question);
|
|
Packit |
8ea169 |
free(question);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!response)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Cancelled by user"));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
/* Upload the archive. */
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"POST /create HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Type: application/x-xz-compressed-tar\r\n"
|
|
Packit |
8ea169 |
"Content-Length: %lld\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"X-Task-Type: %d\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
cfg.url, (long long)file_stat.st_size, task_type,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d"),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
printf(_("Uploading %s\n"), human_size);
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_free(human_size);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
int result = 0;
|
|
Packit |
8ea169 |
int i;
|
|
Packit |
8ea169 |
char buf[32768];
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
time_t start, now;
|
|
Packit |
8ea169 |
time(&start;;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for (i = 0;; ++i)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
time(&now;;
|
|
Packit |
8ea169 |
if (now - start >= delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
time(&start;;
|
|
Packit |
8ea169 |
int progress = 100 * i * sizeof(buf) / file_stat.st_size;
|
|
Packit |
8ea169 |
if (progress > 100)
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
printf(_("Uploading %d%%\n"), progress);
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int r = read(tempfd, buf, sizeof(buf));
|
|
Packit |
8ea169 |
if (r <= 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (r == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno)
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
perror_msg_and_die(_("Failed to read from a pipe"));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
written = PR_Send(tcp_sock, buf, r,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Print error message, but do not exit. We need to check
|
|
Packit |
8ea169 |
if the server send some explanation regarding the
|
|
Packit |
8ea169 |
error. */
|
|
Packit |
8ea169 |
result = 1;
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg(_("Failed to send data: NSS error %d (%s): %s"),
|
|
Packit |
8ea169 |
PR_GetError(),
|
|
Packit |
8ea169 |
PR_ErrorToName(PR_GetError()),
|
|
Packit |
8ea169 |
PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
close(tempfd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
puts(_("Upload successful"));
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Read the HTTP header of the response from server. */
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
if (!http_body)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
if (response_code == 500 || response_code == 507)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die("%s", http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (response_code == 403)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert(_("Your problem directory is corrupted and can not "
|
|
Packit |
8ea169 |
"be processed by the Retrace server."));
|
|
Packit |
8ea169 |
error_msg_and_die(_("The archive contains malicious files (such as symlinks) "
|
|
Packit |
8ea169 |
"and thus can not be processed."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (response_code != 201)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"), response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(http_body);
|
|
Packit |
8ea169 |
*task_id = http_get_header_value(http_response, "X-Task-Id");
|
|
Packit |
8ea169 |
if (!*task_id)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing X-Task-Id."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
*task_password = http_get_header_value(http_response, "X-Task-Password");
|
|
Packit |
8ea169 |
if (!*task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing X-Task-Password."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (delay)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
puts(_("Retrace job started"));
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int run_create(bool delete_temp_archive)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *task_id, *task_password;
|
|
Packit |
8ea169 |
int result = create(delete_temp_archive, &task_id, &task_password);
|
|
Packit |
8ea169 |
if (0 != result)
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
printf(_("Task Id: %s\nTask Password: %s\n"), task_id, task_password);
|
|
Packit |
8ea169 |
free(task_id);
|
|
Packit |
8ea169 |
free(task_password);
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Caller must free task_status and status_message */
|
|
Packit |
8ea169 |
static void status(const char *task_id,
|
|
Packit |
8ea169 |
const char *task_password,
|
|
Packit |
8ea169 |
char **task_status,
|
|
Packit |
8ea169 |
char **status_message)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /%s HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"X-Task-Password: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
task_id, cfg.url, task_password,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d"),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
if (!*http_body)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
if (response_code != 200)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
*task_status = http_get_header_value(http_response, "X-Task-Status");
|
|
Packit |
8ea169 |
if (!*task_status)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing X-Task-Status."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
*status_message = http_body;
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void run_status(const char *task_id, const char *task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *task_status;
|
|
Packit |
8ea169 |
char *status_message;
|
|
Packit |
8ea169 |
status(task_id, task_password, &task_status, &status_message);
|
|
Packit |
8ea169 |
printf(_("Task Status: %s\n%s\n"), task_status, status_message);
|
|
Packit |
8ea169 |
free(task_status);
|
|
Packit |
8ea169 |
free(status_message);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Caller must free backtrace */
|
|
Packit |
8ea169 |
static void backtrace(const char *task_id, const char *task_password,
|
|
Packit |
8ea169 |
char **backtrace)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /%s/backtrace HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"X-Task-Password: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
task_id, cfg.url, task_password,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d."),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
if (!http_body)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
if (response_code != 200)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
*backtrace = http_body;
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void run_backtrace(const char *task_id, const char *task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *backtrace_text;
|
|
Packit |
8ea169 |
backtrace(task_id, task_password, &backtrace_text);
|
|
Packit |
8ea169 |
printf("%s", backtrace_text);
|
|
Packit |
8ea169 |
free(backtrace_text);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* This is not robust at all but will work for now */
|
|
Packit |
8ea169 |
static int get_exploitable_rating(const char *exploitable_text)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *colon = strrchr(exploitable_text, ':');
|
|
Packit |
8ea169 |
int result;
|
|
Packit |
8ea169 |
if (!colon || sscanf(colon, ": %d", &result) != 1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Unable to determine exploitable rating");
|
|
Packit |
8ea169 |
return -1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_notice("Exploitable rating: %d", result);
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Caller must free exploitable_text */
|
|
Packit |
8ea169 |
static void exploitable(const char *task_id, const char *task_password,
|
|
Packit |
8ea169 |
char **exploitable_text)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /%s/exploitable HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"X-Task-Password: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
task_id, cfg.url, task_password,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d."),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
if (!http_body)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* 404 = exploitability results not available
|
|
Packit |
8ea169 |
200 = OK
|
|
Packit |
8ea169 |
anything else = error */
|
|
Packit |
8ea169 |
if (response_code == 404)
|
|
Packit |
8ea169 |
*exploitable_text = NULL;
|
|
Packit |
8ea169 |
else if (response_code == 200)
|
|
Packit |
8ea169 |
*exploitable_text = http_body;
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void run_exploitable(const char *task_id, const char *task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *exploitable_text;
|
|
Packit |
8ea169 |
exploitable(task_id, task_password, &exploitable_text);
|
|
Packit |
8ea169 |
if (exploitable_text)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
printf("%s\n", exploitable_text);
|
|
Packit |
8ea169 |
free(exploitable_text);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
puts("No exploitability information available.");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void run_log(const char *task_id, const char *task_password)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
PRFileDesc *tcp_sock, *ssl_sock;
|
|
Packit |
8ea169 |
ssl_connect(&cfg, &tcp_sock, &ssl_sock);
|
|
Packit |
8ea169 |
struct strbuf *http_request = strbuf_new();
|
|
Packit |
8ea169 |
strbuf_append_strf(http_request,
|
|
Packit |
8ea169 |
"GET /%s/log HTTP/1.1\r\n"
|
|
Packit |
8ea169 |
"Host: %s\r\n"
|
|
Packit |
8ea169 |
"X-Task-Password: %s\r\n"
|
|
Packit |
8ea169 |
"Content-Length: 0\r\n"
|
|
Packit |
8ea169 |
"Connection: close\r\n"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"%s"
|
|
Packit |
8ea169 |
"\r\n",
|
|
Packit |
8ea169 |
task_id, cfg.url, task_password,
|
|
Packit |
8ea169 |
lang.accept_charset,
|
|
Packit |
8ea169 |
lang.accept_language
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
PRInt32 written = PR_Send(tcp_sock, http_request->buf, http_request->len,
|
|
Packit |
8ea169 |
/*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
|
|
Packit |
8ea169 |
if (written == -1)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_connection_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Failed to send HTTP header of length %d: NSS error %d."),
|
|
Packit |
8ea169 |
http_request->len, PR_GetError());
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
strbuf_free(http_request);
|
|
Packit |
8ea169 |
char *http_response = tcp_read_response(tcp_sock);
|
|
Packit |
8ea169 |
char *http_body = http_get_body(http_response);
|
|
Packit |
8ea169 |
if (!http_body)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Invalid response from server: missing HTTP message body."));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (http_show_headers)
|
|
Packit |
8ea169 |
http_print_headers(stderr, http_response);
|
|
Packit |
8ea169 |
int response_code = http_get_response_code(http_response);
|
|
Packit |
8ea169 |
if (response_code != 200)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert_server_error(cfg.url);
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unexpected HTTP response from server: %d\n%s"),
|
|
Packit |
8ea169 |
response_code, http_body);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
puts(http_body);
|
|
Packit |
8ea169 |
free(http_body);
|
|
Packit |
8ea169 |
free(http_response);
|
|
Packit |
8ea169 |
ssl_disconnect(ssl_sock);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int run_batch(bool delete_temp_archive)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *task_id, *task_password;
|
|
Packit |
8ea169 |
int retcode = create(delete_temp_archive, &task_id, &task_password);
|
|
Packit |
8ea169 |
if (0 != retcode)
|
|
Packit |
8ea169 |
return retcode;
|
|
Packit |
8ea169 |
char *task_status = xstrdup("");
|
|
Packit |
8ea169 |
char *status_message = xstrdup("");
|
|
Packit |
8ea169 |
int status_delay = delay ? delay : 10;
|
|
Packit |
8ea169 |
int dots = 0;
|
|
Packit |
8ea169 |
while (0 != strncmp(task_status, "FINISHED", strlen("finished")))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *previous_status_message = status_message;
|
|
Packit |
8ea169 |
free(task_status);
|
|
Packit |
8ea169 |
sleep(status_delay);
|
|
Packit |
8ea169 |
status(task_id, task_password, &task_status, &status_message);
|
|
Packit |
8ea169 |
if (g_verbose > 0 || 0 != strcmp(previous_status_message, status_message))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (dots)
|
|
Packit |
8ea169 |
{ /* A same message was received and a period was printed instead
|
|
Packit |
8ea169 |
* but the period wasn't followed by new line and now we are
|
|
Packit |
8ea169 |
* goning to print a new message thus we want to start at next line
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
dots = 0;
|
|
Packit |
8ea169 |
putchar('\n');
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
puts(status_message);
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (dots >= MAX_DOTS_PER_LINE)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
dots = 0;
|
|
Packit |
8ea169 |
putchar('\n');
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
++dots;
|
|
Packit |
8ea169 |
client_log(".");
|
|
Packit |
8ea169 |
fflush(stdout);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(previous_status_message);
|
|
Packit |
8ea169 |
previous_status_message = status_message;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
if (0 == strcmp(task_status, "FINISHED_SUCCESS"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *backtrace_text;
|
|
Packit |
8ea169 |
backtrace(task_id, task_password, &backtrace_text);
|
|
Packit |
8ea169 |
char *exploitable_text = NULL;
|
|
Packit |
8ea169 |
if (task_type == TASK_RETRACE)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
exploitable(task_id, task_password, &exploitable_text);
|
|
Packit |
8ea169 |
if (!exploitable_text)
|
|
Packit |
8ea169 |
log_notice("No exploitable data available");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (dump_dir_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, 0/* flags */);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
free(backtrace_text);
|
|
Packit |
8ea169 |
xfunc_die();
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* the result of TASK_VMCORE is not backtrace, but kernel log */
|
|
Packit |
8ea169 |
const char *target = task_type == TASK_VMCORE ? FILENAME_KERNEL_LOG : FILENAME_BACKTRACE;
|
|
Packit |
8ea169 |
dd_save_text(dd, target, backtrace_text);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (exploitable_text)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int exploitable_rating = get_exploitable_rating(exploitable_text);
|
|
Packit |
8ea169 |
if (exploitable_rating >= MIN_EXPLOITABLE_RATING)
|
|
Packit |
8ea169 |
dd_save_text(dd, FILENAME_EXPLOITABLE, exploitable_text);
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
log_notice("Not saving exploitable data, rating < %d",
|
|
Packit |
8ea169 |
MIN_EXPLOITABLE_RATING);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
printf("%s\n", backtrace_text);
|
|
Packit |
8ea169 |
if (exploitable_text)
|
|
Packit |
8ea169 |
printf("%s\n", exploitable_text);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(backtrace_text);
|
|
Packit |
8ea169 |
free(exploitable_text);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
alert(_("Retrace failed. Try again later and if the problem persists "
|
|
Packit |
8ea169 |
"report this issue please."));
|
|
Packit |
8ea169 |
run_log(task_id, task_password);
|
|
Packit |
8ea169 |
retcode = 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(task_status);
|
|
Packit |
8ea169 |
free(status_message);
|
|
Packit |
8ea169 |
free(task_id);
|
|
Packit |
8ea169 |
free(task_password);
|
|
Packit |
8ea169 |
return retcode;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int main(int argc, char **argv)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
setlocale(LC_ALL, "");
|
|
Packit |
8ea169 |
#if ENABLE_NLS
|
|
Packit |
8ea169 |
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
Packit |
8ea169 |
textdomain(PACKAGE);
|
|
Packit |
8ea169 |
#endif
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_init(argv);
|
|
Packit |
8ea169 |
get_language(&lang);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *task_id = NULL;
|
|
Packit |
8ea169 |
const char *task_password = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
enum {
|
|
Packit |
8ea169 |
OPT_verbose = 1 << 0,
|
|
Packit |
8ea169 |
OPT_syslog = 1 << 1,
|
|
Packit |
8ea169 |
OPT_insecure = 1 << 2,
|
|
Packit |
8ea169 |
OPT_no_pkgchk = 1 << 3,
|
|
Packit |
8ea169 |
OPT_url = 1 << 4,
|
|
Packit |
8ea169 |
OPT_port = 1 << 5,
|
|
Packit |
8ea169 |
OPT_headers = 1 << 6,
|
|
Packit |
8ea169 |
OPT_group_1 = 1 << 7,
|
|
Packit |
8ea169 |
OPT_dir = 1 << 8,
|
|
Packit |
8ea169 |
OPT_core = 1 << 9,
|
|
Packit |
8ea169 |
OPT_delay = 1 << 10,
|
|
Packit |
8ea169 |
OPT_no_unlink = 1 << 11,
|
|
Packit |
8ea169 |
OPT_group_2 = 1 << 12,
|
|
Packit |
8ea169 |
OPT_task = 1 << 13,
|
|
Packit |
8ea169 |
OPT_password = 1 << 14
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Keep enum above and order of options below in sync! */
|
|
Packit |
8ea169 |
struct options options[] = {
|
|
Packit |
8ea169 |
OPT__VERBOSE(&g_verbose),
|
|
Packit |
8ea169 |
OPT_BOOL('s', "syslog", NULL, _("log to syslog")),
|
|
Packit |
8ea169 |
OPT_BOOL('k', "insecure", NULL,
|
|
Packit |
8ea169 |
_("allow insecure connection to retrace server")),
|
|
Packit |
8ea169 |
OPT_BOOL(0, "no-pkgcheck", NULL,
|
|
Packit |
8ea169 |
_("do not check whether retrace server is able to "
|
|
Packit |
8ea169 |
"process given package before uploading the archive")),
|
|
Packit |
8ea169 |
OPT_STRING(0, "url", &(cfg.url), "URL",
|
|
Packit |
8ea169 |
_("retrace server URL")),
|
|
Packit |
8ea169 |
OPT_INTEGER(0, "port", &(cfg.port),
|
|
Packit |
8ea169 |
_("retrace server port")),
|
|
Packit |
8ea169 |
OPT_BOOL(0, "headers", NULL,
|
|
Packit |
8ea169 |
_("(debug) show received HTTP headers")),
|
|
Packit |
8ea169 |
OPT_GROUP(_("For create and batch operations")),
|
|
Packit |
8ea169 |
OPT_STRING('d', "dir", &dump_dir_name, "DIR",
|
|
Packit |
8ea169 |
_("read data from ABRT problem directory")),
|
|
Packit |
8ea169 |
OPT_STRING('c', "core", &coredump, "COREDUMP",
|
|
Packit |
8ea169 |
_("read data from coredump")),
|
|
Packit |
8ea169 |
OPT_INTEGER('l', "status-delay", &delay,
|
|
Packit |
8ea169 |
_("Delay for polling operations")),
|
|
Packit |
8ea169 |
OPT_BOOL(0, "no-unlink", NULL,
|
|
Packit |
8ea169 |
_("(debug) do not delete temporary archive created"
|
|
Packit |
8ea169 |
" from dump dir in "LARGE_DATA_TMP_DIR)),
|
|
Packit |
8ea169 |
OPT_GROUP(_("For status, backtrace, and log operations")),
|
|
Packit |
8ea169 |
OPT_STRING('t', "task", &task_id, "ID",
|
|
Packit |
8ea169 |
_("id of your task on server")),
|
|
Packit |
8ea169 |
OPT_STRING('p', "password", &task_password, "PWD",
|
|
Packit |
8ea169 |
_("password of your task on server")),
|
|
Packit |
8ea169 |
OPT_END()
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *usage = _("abrt-retrace-client <operation> [options]\n"
|
|
Packit |
8ea169 |
"Operations: create/status/backtrace/log/batch/exploitable");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *env_url = getenv("RETRACE_SERVER_URL");
|
|
Packit |
8ea169 |
if (env_url)
|
|
Packit |
8ea169 |
cfg.url = env_url;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *env_port = getenv("RETRACE_SERVER_PORT");
|
|
Packit |
8ea169 |
if (env_port)
|
|
Packit |
8ea169 |
cfg.port = xatou(env_port);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *env_delay = getenv("ABRT_STATUS_DELAY");
|
|
Packit |
8ea169 |
if (env_delay)
|
|
Packit |
8ea169 |
delay = xatou(env_delay);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *env_insecure = getenv("RETRACE_SERVER_INSECURE");
|
|
Packit |
8ea169 |
if (env_insecure)
|
|
Packit |
8ea169 |
cfg.ssl_allow_insecure = strncmp(env_insecure, "insecure", strlen("insecure")) == 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unsigned opts = parse_opts(argc, argv, options, usage);
|
|
Packit |
8ea169 |
if (opts & OPT_syslog)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
logmode = LOGMODE_JOURNAL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
const char *operation = NULL;
|
|
Packit |
8ea169 |
if (optind < argc)
|
|
Packit |
8ea169 |
operation = argv[optind];
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
show_usage_and_die(usage, options);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!cfg.ssl_allow_insecure)
|
|
Packit |
8ea169 |
cfg.ssl_allow_insecure = opts & OPT_insecure;
|
|
Packit |
8ea169 |
http_show_headers = opts & OPT_headers;
|
|
Packit |
8ea169 |
no_pkgcheck = opts & OPT_no_pkgchk;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Initialize NSS */
|
|
Packit |
8ea169 |
SECMODModule *mod;
|
|
Packit |
8ea169 |
nss_init(&mod);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Run the desired operation. */
|
|
Packit |
8ea169 |
int result = 0;
|
|
Packit |
8ea169 |
if (0 == strcasecmp(operation, "create"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!dump_dir_name && !coredump)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Either problem directory or coredump is needed."));
|
|
Packit |
8ea169 |
result = run_create(0 == (opts & OPT_no_unlink));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp(operation, "batch"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!dump_dir_name && !coredump)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Either problem directory or coredump is needed."));
|
|
Packit |
8ea169 |
result = run_batch(0 == (opts & OPT_no_unlink));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp(operation, "status"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!task_id)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task id is needed."));
|
|
Packit |
8ea169 |
if (!task_password)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task password is needed."));
|
|
Packit |
8ea169 |
run_status(task_id, task_password);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp(operation, "backtrace"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!task_id)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task id is needed."));
|
|
Packit |
8ea169 |
if (!task_password)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task password is needed."));
|
|
Packit |
8ea169 |
run_backtrace(task_id, task_password);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp(operation, "log"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!task_id)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task id is needed."));
|
|
Packit |
8ea169 |
if (!task_password)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task password is needed."));
|
|
Packit |
8ea169 |
run_log(task_id, task_password);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (0 == strcasecmp(operation, "exploitable"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!task_id)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task id is needed."));
|
|
Packit |
8ea169 |
if (!task_password)
|
|
Packit |
8ea169 |
error_msg_and_die(_("Task password is needed."));
|
|
Packit |
8ea169 |
run_exploitable(task_id, task_password);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
error_msg_and_die(_("Unknown operation: %s."), operation);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Shutdown NSS. */
|
|
Packit |
8ea169 |
nss_close(mod);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|