diff options
| author | Karel Klic <kklic@redhat.com> | 2010-01-18 13:19:54 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2010-01-18 13:19:54 +0100 |
| commit | 4267cbcc29781ddcac00e259dfe05f3a26fbc2ec (patch) | |
| tree | 213e47138967f1e7af4ee9ff9a3f2ed861cb5815 /lib | |
| parent | b2d1bd9e4f387c5a014d3002d741f25421c37aac (diff) | |
| parent | b41833ed61f7b579d2a46b26d261616c21a6ae32 (diff) | |
| download | abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.tar.gz abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.tar.xz abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.zip | |
Merge branch 'master' of git://git.fedorahosted.org/git/abrt
Diffstat (limited to 'lib')
37 files changed, 903 insertions, 301 deletions
diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp index 2d065f6..6f0f8d7 100644 --- a/lib/Plugins/Bugzilla.cpp +++ b/lib/Plugins/Bugzilla.cpp @@ -13,6 +13,9 @@ #define XML_RPC_SUFFIX "/xmlrpc.cgi" +/* + * TODO: npajkovs: better deallocation of xmlrpc value + */ /* * Static namespace for xmlrpc stuff. @@ -39,7 +42,8 @@ void ctx::login(const char* login, const char* passwd) xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s})", "login", login, "password", passwd); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.login", param, &result); @@ -62,14 +66,16 @@ void ctx::logout() xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", ""); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.logout", param, &result); xmlrpc_DECREF(param); if (result) xmlrpc_DECREF(result); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); } bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) @@ -77,23 +83,36 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) xmlrpc_env env; xmlrpc_env_init(&env); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", to_string(bug_id).c_str()); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.getBug", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* reporter_member = NULL; xmlrpc_struct_find_value(&env, result, "reporter", &reporter_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (reporter_member) { const char* reporter = NULL; xmlrpc_read_string(&env, reporter_member, &reporter); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(reporter_member); + throw_xml_fault(&env); + } bool eq = (strcmp(reporter, login) == 0); free((void*)reporter); @@ -107,7 +126,11 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) xmlrpc_value* cc_member = NULL; xmlrpc_struct_find_value(&env, result, "cc", &cc_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (cc_member) { @@ -117,11 +140,22 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) { xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, cc_member, i, &item); // Correct - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(cc_member); + throw_xml_fault(&env); + } const char* cc = NULL; xmlrpc_read_string(&env, item, &cc); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(cc_member); + xmlrpc_DECREF(item); + throw_xml_fault(&env); + } bool eq = (strcmp(cc, login) == 0); free((void*)cc); @@ -145,15 +179,19 @@ void ctx::add_plus_one_cc(uint32_t bug_id, const char* login) xmlrpc_env env; xmlrpc_env_init(&env); - xmlrpc_value* param = xmlrpc_build_value(&env, "({s:i,s:{s:(s)}})", "ids", bug_id, "updates", "add_cc", login); - throw_if_xml_fault_occurred(&env); + // fails only when you write query. when it's done it never fails. + xmlrpc_value* param = xmlrpc_build_value(&env, "({s:i,s:{s:(s)}})", "ids", bug_id, "updates", "add_cc", login); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.update", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) + xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_DECREF(result); - xmlrpc_DECREF(param); } int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID) @@ -163,36 +201,61 @@ int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID) std::string query = ssprintf("ALL component:\"%s\" statuswhiteboard:\"%s\"", component, UUID); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s})", "quicksearch", query.c_str()); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.search", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* bugs_member = NULL; xmlrpc_struct_find_value(&env, result, "bugs", &bugs_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (bugs_member) { // when array size is equal 0 that means no bug reported uint32_t array_size = xmlrpc_array_size(&env, bugs_member); - throw_if_xml_fault_occurred(&env); - if (array_size == 0) + if (env.fault_occurred) { + xmlrpc_DECREF(result); xmlrpc_DECREF(bugs_member); + throw_xml_fault(&env); + } + else if (array_size == 0) + { xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); return -1; } xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, bugs_member, 0, &item); // Correct - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); + throw_xml_fault(&env); + } + xmlrpc_value* bug = NULL; xmlrpc_struct_find_value(&env, item, "bug_id", &bug); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); + xmlrpc_DECREF(item); + throw_xml_fault(&env); + } if (bug) { @@ -236,6 +299,7 @@ uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport) std::string version; parse_release(release.c_str(), product, version); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s,s:s,s:s,s:s,s:s,s:s})", "product", product.c_str(), "component", component.c_str(), @@ -245,27 +309,39 @@ uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport) "status_whiteboard", status_whiteboard.c_str(), "platform", arch.c_str() ); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.create", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) + xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* id; xmlrpc_struct_find_value(&env, result, "id", &id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } xmlrpc_int bug_id = -1; if (id) { xmlrpc_read_int(&env, id, &bug_id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(id); + throw_xml_fault(&env); + } log("New bug id: %i", bug_id); update_client(_("New bug id: %i"), bug_id); } xmlrpc_DECREF(result); - xmlrpc_DECREF(param); xmlrpc_DECREF(id); return bug_id; } @@ -287,6 +363,7 @@ void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCra if (type == CD_ATT) { char *encoded64 = encode_base64(content.c_str(), content.length()); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "(s{s:s,s:s,s:s,s:s})", bug_id_str, "description", ("File: " + filename).c_str(), @@ -295,12 +372,18 @@ void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCra "data", encoded64 ); free(encoded64); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.addAttachment", param, &result); - throw_if_xml_fault_occurred(&env); - xmlrpc_DECREF(result); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } + xmlrpc_DECREF(result); } } } diff --git a/lib/Plugins/CCpp.conf b/lib/Plugins/CCpp.conf index dfdbec8..153efb9 100644 --- a/lib/Plugins/CCpp.conf +++ b/lib/Plugins/CCpp.conf @@ -1,4 +1,5 @@ # Configuration file for CCpp hook and plugin +Enabled = yes # If you also want to dump file named "core" # in crashed process' current dir, set to "yes" diff --git a/lib/Plugins/CCpp.cpp b/lib/Plugins/CCpp.cpp index 1a01c01..e0db9cf 100644 --- a/lib/Plugins/CCpp.cpp +++ b/lib/Plugins/CCpp.cpp @@ -24,9 +24,8 @@ #include <sstream> #include <set> #include <iomanip> -#include <nss.h> -#include <sechash.h> -#include <sysexits.h> +//#include <nss.h> +//#include <sechash.h> #include "abrtlib.h" #include "CCpp.h" #include "ABRTException.h" @@ -34,6 +33,8 @@ #include "CommLayerInner.h" #include "Polkit.h" +#include "CCpp_sha1.h" + using namespace std; #define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern" @@ -54,11 +55,13 @@ CAnalyzerCCpp::CAnalyzerCCpp() : static string CreateHash(const char *pInput) { - string ret; - HASHContext* hc; - unsigned char hash[SHA1_LENGTH]; unsigned int len; +#if 0 +{ + char hash_str[SHA1_LENGTH*2 + 1]; + unsigned char hash[SHA1_LENGTH]; + HASHContext *hc; hc = HASH_Create(HASH_AlgSHA1); if (!hc) { @@ -69,7 +72,6 @@ static string CreateHash(const char *pInput) HASH_End(hc, hash, &len, sizeof(hash)); HASH_Destroy(hc); - char hash_str[SHA1_LENGTH*2 + 1]; char *d = hash_str; unsigned char *s = hash; while (len) @@ -80,6 +82,29 @@ static string CreateHash(const char *pInput) len--; } *d = '\0'; +//log("hash1:%s str:'%s'", hash_str, pInput); +} +#endif + + char hash_str[SHA1_RESULT_LEN*2 + 1]; + unsigned char hash2[SHA1_RESULT_LEN]; + sha1_ctx_t sha1ctx; + sha1_begin(&sha1ctx); + sha1_hash(pInput, strlen(pInput), &sha1ctx); + sha1_end(hash2, &sha1ctx); + len = SHA1_RESULT_LEN; + + char *d = hash_str; + unsigned char *s = hash2; + while (len) + { + *d++ = "0123456789abcdef"[*s >> 4]; + *d++ = "0123456789abcdef"[*s & 0xf]; + s++; + len--; + } + *d = '\0'; +//log("hash2:%s str:'%s'", hash_str, pInput); return hash_str; } @@ -99,54 +124,28 @@ static string concat_str_vector(char **strings) /* Returns status. See `man 2 wait` for status information. */ static int ExecVP(char **pArgs, uid_t uid, int redirect_stderr, string& pOutput) { - int pipeout[2]; - pid_t child; - - xpipe(pipeout); - child = fork(); - if (child == -1) - { - perror_msg_and_die("fork"); - } - if (child == 0) - { - VERB1 log("Executing: %s", concat_str_vector(pArgs).c_str()); - close(pipeout[0]); /* read side of the pipe */ - xmove_fd(pipeout[1], STDOUT_FILENO); - /* Make sure stdin is safely open to nothing */ - xmove_fd(xopen("/dev/null", O_RDONLY), STDIN_FILENO); - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - setsid(); - - /* Nuke everything which may make setlocale() switch to non-POSIX locale: - * we need to avoid having gdb output in some obscure language. - */ - unsetenv("LANG"); - unsetenv("LC_ALL"); - unsetenv("LC_COLLATE"); - unsetenv("LC_CTYPE"); - unsetenv("LC_MESSAGES"); - unsetenv("LC_MONETARY"); - unsetenv("LC_NUMERIC"); - unsetenv("LC_TIME"); - - if (redirect_stderr) - { - /* We want parent to see errors in the same stream */ - xdup2(STDOUT_FILENO, STDERR_FILENO); - } - execvp(pArgs[0], pArgs); - /* VERB1 since sometimes we expect errors here */ - VERB1 perror_msg("Can't execute '%s'", pArgs[0]); - exit(1); - } + /* Nuke everything which may make setlocale() switch to non-POSIX locale: + * we need to avoid having gdb output in some obscure language. + */ + static const char *const unsetenv_vec[] = { + "LANG", + "LC_ALL", + "LC_COLLATE", + "LC_CTYPE", + "LC_MESSAGES", + "LC_MONETARY", + "LC_NUMERIC", + "LC_TIME", + NULL + }; + + int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETGUID | EXECFLG_SETSID | EXECFLG_QUIET; + if (redirect_stderr) + flags |= EXECFLG_ERR2OUT; + VERB1 flags &= ~EXECFLG_QUIET; - close(pipeout[1]); /* write side of the pipe */ + int pipeout[2]; + pid_t child = fork_execv_on_steroids(flags, pArgs, pipeout, (char**)unsetenv_vec, /*dir:*/ NULL, uid); int r; char buff[1024]; @@ -155,8 +154,8 @@ static int ExecVP(char **pArgs, uid_t uid, int redirect_stderr, string& pOutput) buff[r] = '\0'; pOutput += buff; } - close(pipeout[0]); + int status; waitpid(child, &status, 0); /* prevent having zombie child process */ @@ -379,6 +378,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, int pipeout[2]; //TODO: can we use ExecVP? xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -394,7 +394,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir); /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); + char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu", (long)getpid(), (long)time(NULL)); /* log() goes to stderr/syslog, it's ok to use it here */ VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, debuginfo_dirs); /* We want parent to see errors in the same stream */ @@ -545,6 +545,8 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) { log(_("Getting global universal unique identification...")); +//TODO: convert to fork_execv_on_steroids(), nuke static concat_str_vector + string backtrace_path = concat_path_file(pDebugDumpDir, FILENAME_BACKTRACE); string executable; string package; @@ -574,6 +576,8 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) int pipeout[2]; xpipe(pipeout); /* stdout of abrt-backtrace */ + + fflush(NULL); pid_t child = fork(); if (child == -1) perror_msg_and_die("fork"); @@ -617,13 +621,29 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) { perror_msg("abrt-backtrace not executed properly, " "status: %x signal: %d", status, WIFSIGNALED(status)); - } else + } + else { int exit_status = WEXITSTATUS(status); - if (exit_status != 0) + if (exit_status == 79) /* EX_PARSINGFAILED */ { + /* abrt-backtrace returns alternative backtrace + representation in this case, so everything will work + as expected except worse duplication detection */ + log_msg("abrt-backtrace failed to parse the backtrace"); + } + else if (exit_status == 80) /* EX_THREADDETECTIONFAILED */ + { + /* abrt-backtrace returns backtrace with all threads + in this case, so everything will work as expected + except worse duplication detection */ + log_msg("abrt-backtrace failed to determine crash frame"); + } + else if (exit_status != 0) + { + /* this is unexpected problem and it should be investigated */ error_msg("abrt-backtrace run failed, exit value: %d", - exit_status); + exit_status); } } @@ -635,8 +655,9 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) return CreateHash(hash_base.c_str()); } -static bool DebuginfoCheckPolkit(int uid) +static bool DebuginfoCheckPolkit(uid_t uid) { + fflush(NULL); int child_pid = fork(); if (child_pid < 0) { @@ -653,8 +674,10 @@ static bool DebuginfoCheckPolkit(int uid) //parent int status; - if (waitpid(child_pid, &status, 0) > 0 && WEXITSTATUS(status) == 0) - { + if (waitpid(child_pid, &status, 0) > 0 + && WIFEXITED(status) + && WEXITSTATUS(status) == 0 + ) { return true; //authorization OK } log("UID %d is not authorized to install debuginfos", uid); diff --git a/lib/Plugins/CCpp_sha1.cpp b/lib/Plugins/CCpp_sha1.cpp new file mode 100644 index 0000000..86a9e83 --- /dev/null +++ b/lib/Plugins/CCpp_sha1.cpp @@ -0,0 +1,214 @@ +/* vi: set sw=4 ts=4: */ +/* + * Based on shasum from http://www.netsw.org/crypto/hash/ + * Majorly hacked up to use Dr Brian Gladman's sha1 code + * + * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * --------------------------------------------------------------------------- + * Issue Date: 10/11/2002 + * + * This is a byte oriented version of SHA1 that operates on arrays of bytes + * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * + * --------------------------------------------------------------------------- + */ +#include "abrtlib.h" +#include "CCpp_sha1.h" + +#if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ +# define SHA1_BIG_ENDIAN 1 +# define SHA1_LITTLE_ENDIAN 0 +#elif __BYTE_ORDER == __BIG_ENDIAN +# define SHA1_BIG_ENDIAN 1 +# define SHA1_LITTLE_ENDIAN 0 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define SHA1_BIG_ENDIAN 0 +# define SHA1_LITTLE_ENDIAN 1 +#else +# error "Can't determine endianness" +#endif + + +#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) +/* for sha512: */ +#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) +#if SHA1_LITTLE_ENDIAN +static inline uint64_t hton64(uint64_t v) +{ + return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); +} +#else +#define hton64(v) (v) +#endif +#define ntoh64(v) hton64(v) + +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +#if defined(__GNUC__) && __GNUC__ >= 2 +# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0) +#else +# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0) +#endif + + +/* Some arch headers have conflicting defines */ +#undef ch +#undef parity +#undef maj +#undef rnd + +static void sha1_process_block64(sha1_ctx_t *ctx) +{ + unsigned t; + uint32_t W[80], a, b, c, d, e; + const uint32_t *words = (uint32_t*) ctx->wbuffer; + + for (t = 0; t < 16; ++t) { + W[t] = ntohl(*words); + words++; + } + + for (/*t = 16*/; t < 80; ++t) { + uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; + W[t] = rotl32(T, 1); + } + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + +/* Reverse byte order in 32-bit words */ +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +/* A normal version as set out in the FIPS. This version uses */ +/* partial loop unrolling and is optimised for the Pentium 4 */ +#define rnd(f,k) \ + do { \ + uint32_t T = a; \ + a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ + e = d; \ + d = c; \ + c = rotl32(b, 30); \ + b = T; \ + } while (0) + + for (t = 0; t < 20; ++t) + rnd(ch, 0x5a827999); + + for (/*t = 20*/; t < 40; ++t) + rnd(parity, 0x6ed9eba1); + + for (/*t = 40*/; t < 60; ++t) + rnd(maj, 0x8f1bbcdc); + + for (/*t = 60*/; t < 80; ++t) + rnd(parity, 0xca62c1d6); +#undef ch +#undef parity +#undef maj +#undef rnd + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; +} + +void sha1_begin(sha1_ctx_t *ctx) +{ + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; + ctx->total64 = 0; + ctx->process_block = sha1_process_block64; +} + +static const uint32_t init256[] = { + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 +}; +static const uint32_t init512_lo[] = { + 0xf3bcc908, + 0x84caa73b, + 0xfe94f82b, + 0x5f1d36f1, + 0xade682d1, + 0x2b3e6c1f, + 0xfb41bd6b, + 0x137e2179 +}; + +/* Used also for sha256 */ +void sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx) +{ + unsigned in_buf = ctx->total64 & 63; + unsigned add = 64 - in_buf; + + ctx->total64 += len; + + while (len >= add) { /* transfer whole blocks while possible */ + memcpy(ctx->wbuffer + in_buf, buffer, add); + buffer = (const char *)buffer + add; + len -= add; + add = 64; + in_buf = 0; + ctx->process_block(ctx); + } + + memcpy(ctx->wbuffer + in_buf, buffer, len); +} + +/* Used also for sha256 */ +void sha1_end(void *resbuf, sha1_ctx_t *ctx) +{ + unsigned pad, in_buf; + + in_buf = ctx->total64 & 63; + /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ + ctx->wbuffer[in_buf++] = 0x80; + + /* This loop iterates either once or twice, no more, no less */ + while (1) { + pad = 64 - in_buf; + memset(ctx->wbuffer + in_buf, 0, pad); + in_buf = 0; + /* Do we have enough space for the length count? */ + if (pad >= 8) { + /* Store the 64-bit counter of bits in the buffer in BE format */ + uint64_t t = ctx->total64 << 3; + t = hton64(t); + /* wbuffer is suitably aligned for this */ + *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; + } + ctx->process_block(ctx); + if (pad >= 8) + break; + } + + in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8; + /* This way we do not impose alignment constraints on resbuf: */ + if (SHA1_LITTLE_ENDIAN) { + unsigned i; + for (i = 0; i < in_buf; ++i) + ctx->hash[i] = htonl(ctx->hash[i]); + } + memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf); +} diff --git a/lib/Plugins/CCpp_sha1.h b/lib/Plugins/CCpp_sha1.h new file mode 100644 index 0000000..abadfd9 --- /dev/null +++ b/lib/Plugins/CCpp_sha1.h @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: */ +/* + * Based on shasum from http://www.netsw.org/crypto/hash/ + * Majorly hacked up to use Dr Brian Gladman's sha1 code + * + * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * --------------------------------------------------------------------------- + * Issue Date: 10/11/2002 + * + * This is a byte oriented version of SHA1 that operates on arrays of bytes + * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * + * --------------------------------------------------------------------------- + */ + +#define SHA1_RESULT_LEN (5 * 4) + +typedef struct sha1_ctx_t { + uint32_t hash[8]; /* 5, +3 elements for sha256 */ + uint64_t total64; + uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */ + void (*process_block)(struct sha1_ctx_t*); +} sha1_ctx_t; + +void sha1_begin(sha1_ctx_t *ctx); +void sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx); +void sha1_end(void *resbuf, sha1_ctx_t *ctx); diff --git a/lib/Plugins/Catcut.conf b/lib/Plugins/Catcut.conf index 456d7f8..a0249fd 100644 --- a/lib/Plugins/Catcut.conf +++ b/lib/Plugins/Catcut.conf @@ -1,3 +1,4 @@ +Enabled=1 # Catcut URL CatcutURL = http://127.0.0.1:8080/catcut/xmlrpc # yes means that ssl certificates will not be checked @@ -6,3 +7,4 @@ NoSSLVerify = no Login = gavin # your password Password = junk +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp index a56015d..27b868d 100644 --- a/lib/Plugins/Catcut.cpp +++ b/lib/Plugins/Catcut.cpp @@ -13,7 +13,7 @@ using namespace std; static int -put_stream(const char *pURL, FILE* f, size_t content_length) +put_stream(const char *pURL, FILE* f, off_t content_length) { CURL* curl = xcurl_easy_init(); /* enable uploading */ @@ -22,8 +22,8 @@ put_stream(const char *pURL, FILE* f, size_t content_length) curl_easy_setopt(curl, CURLOPT_URL, pURL); /* file handle: passed to the default callback, it will fread() it */ curl_easy_setopt(curl, CURLOPT_READDATA, f); - /* get file size */ - curl_easy_setopt(curl, CURLOPT_INFILESIZE, content_length); + /* file size */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)content_length); /* everything is done here; result 0 means success */ int result = curl_easy_perform(curl); /* goodbye */ @@ -43,9 +43,9 @@ send_string(const char *pURL, return; } + size_t content_length = strlen(pContent); while (1) { - int content_length = strlen(pContent); FILE* f = fmemopen((void*)pContent, content_length, "r"); if (!f) { @@ -53,7 +53,7 @@ send_string(const char *pURL, } int result = put_stream(pURL, f, content_length); fclose(f); - if (!result) + if (result == 0) return; update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result)); if (--retryCount <= 0) @@ -88,10 +88,9 @@ send_file(const char *pURL, } struct stat buf; fstat(fileno(f), &buf); /* can't fail */ - int content_length = buf.st_size; - int result = put_stream(pURL, f, content_length); + int result = put_stream(pURL, f, buf.st_size); fclose(f); - if (!result) + if (result == 0) return; update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result)); if (--retryCount <= 0) @@ -122,6 +121,7 @@ resolve_relative_url(const char *url, const char *base) } const char *end_of_protocol = strchr(base, ':'); +//TODO: why is this safe?!! string protocol(base, end_of_protocol - base); end_of_protocol += 3; /* skip "://" */ @@ -167,11 +167,14 @@ struct_find_int(xmlrpc_env* env, xmlrpc_value* result, { xmlrpc_value* an_xmlrpc_value; xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); + if (an_xmlrpc_value) { xmlrpc_read_int(env, an_xmlrpc_value, &value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); xmlrpc_DECREF(an_xmlrpc_value); return true; } @@ -184,12 +187,14 @@ struct_find_string(xmlrpc_env* env, xmlrpc_value* result, { xmlrpc_value* an_xmlrpc_value; xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); if (an_xmlrpc_value) { const char* value_s; xmlrpc_read_string(env, an_xmlrpc_value, &value_s); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); value = value_s; xmlrpc_DECREF(an_xmlrpc_value); free((void*)value_s); @@ -228,20 +233,24 @@ ctx::login(const char* login, const char* passwd) xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "(ss)", login, passwd); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.auth", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *cookie_xml; const char *cookie; string cookie_str; xmlrpc_struct_find_value(&env, result, "cookie", &cookie_xml); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_read_string(&env, cookie_xml, &cookie); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); cookie_str = cookie; /* xmlrpc_read_string returns *malloc'ed ptr*. * doc is not very clear on it, but I looked in xmlrpc sources. */ @@ -284,20 +293,24 @@ ctx::new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport) "status_whiteboard", status_whiteboard.c_str(), "platform", arch.c_str() ); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.createTicket", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *bug_id_xml; const char *bug_id; string bug_id_str; xmlrpc_struct_find_value(&env, result, "ticket", &bug_id_xml); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_read_string(&env, bug_id_xml, &bug_id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); bug_id_str = bug_id; log("New bug id: %s", bug_id); update_client(_("New bug id: %s"), bug_id); @@ -321,12 +334,14 @@ ctx::request_upload(const char* auth_cookie, const char* pTicketName, pTicketName, fileName, description); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.requestUpload", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); string URL; bool has_URL = struct_find_string(&env, result, "uri", URL); diff --git a/lib/Plugins/FileTransfer.conf b/lib/Plugins/FileTransfer.conf index 75e5671..c92eaee 100644 --- a/lib/Plugins/FileTransfer.conf +++ b/lib/Plugins/FileTransfer.conf @@ -17,3 +17,4 @@ RetryCount = 3 #how long we wait between we retry the upload (in seconds) RetryDelay = 20 +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp index 60e1e66..b08ecd5 100644 --- a/lib/Plugins/FileTransfer.cpp +++ b/lib/Plugins/FileTransfer.cpp @@ -80,11 +80,7 @@ void CFileTransfer::SendFile(const char *pURL, const char *pFilename) { throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename); } - if (fstat(fileno(f), &buf) == -1) - { - fclose(f); - throw CABRTException(EXCEP_PLUGIN, "Can't stat archive file '%s'", pFilename); - } + fstat(fileno(f), &buf); /* never fails */ curl = xcurl_easy_init(); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); @@ -92,7 +88,7 @@ void CFileTransfer::SendFile(const char *pURL, const char *pFilename) curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str()); /* FILE handle: passed to the default callback, it will fread() it */ curl_easy_setopt(curl, CURLOPT_READDATA, f); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size); /* everything is done here; result 0 means success */ int result = curl_easy_perform(curl); curl_easy_cleanup(curl); @@ -110,13 +106,11 @@ parameter "something" to each filename, now used in create_zip, but can be useful for some future archivers as well */ -static void traverse_directory(const char * directory, void * something, - void (*func)(void *, const char *) ) +static void traverse_directory(const char *directory, void *something, + void (*func)(void *, const char *)) { - DIR * dp; - struct dirent * dirp; - char complete_name[BUFSIZ]; - char * end; + DIR *dp; + struct dirent *dirp; dp = opendir(directory); if (dp == NULL) @@ -127,14 +121,8 @@ static void traverse_directory(const char * directory, void * something, { if (is_regular_file(dirp, directory)) { - end = stpcpy(complete_name, directory); - if (end[-1] != '/') - { - *end++ = '/'; - } - end = stpcpy(end, dirp->d_name); - - func(something, complete_name); + string complete_name = concat_path_file(directory, dirp->d_name); + func(something, complete_name.c_str()); } } closedir(dp); @@ -189,6 +177,7 @@ static void create_targz(const char * archive_name, const char * directory) f = fopen(name_without_gz, "r"); if (f == NULL) { +//TODO: we leak uncompressed tar file on disk?? free(name_without_gz); return; } @@ -234,6 +223,7 @@ static void create_tarbz2(const char * archive_name, const char * directory) f = fopen(archive_name, "w"); if (f == NULL) { +//TODO: we leak uncompressed tar file on disk?? close(tarFD); free(name_without_bz2); return; @@ -320,6 +310,7 @@ void CFileTransfer::Run(const char *pActionDir, const char *pArgs) else if (strcmp(pArgs, "one") == 0) { /* just send one archive */ +//TODO: where are we creating it??!! In cwd, which may well be / ??!!! string archivename = ssprintf("%s-%s%s", hostname, DirBase(pActionDir).c_str(), m_sArchiveType.c_str()); try { diff --git a/lib/Plugins/Firefox.cpp b/lib/Plugins/Firefox.cpp index 92ef4e5..d980755 100644 --- a/lib/Plugins/Firefox.cpp +++ b/lib/Plugins/Firefox.cpp @@ -99,6 +99,8 @@ static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput) pid_t child; xpipe(pipeout); + + fflush(NULL); child = fork(); if (child == -1) { @@ -549,6 +551,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) xpipe(pipein); xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -673,6 +676,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) int pipeout[2]; //TODO: can we use ExecVP? xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -692,7 +696,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir); /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); + char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu", (long)getpid(), (long)time(NULL)); /* log() goes to stderr/syslog, it's ok to use it here */ VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR); execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR, NULL); @@ -839,8 +843,9 @@ std::string CAnalyzerFirefox::GetGlobalUUID(const char *pDebugDumpDir) return CreateHash(package + executable + independentBacktrace); } -static bool DebuginfoCheckPolkit(int uid) +static bool DebuginfoCheckPolkit(uid_t uid) { + fflush(NULL); int child_pid = fork(); if (child_pid < 0) { @@ -857,8 +862,10 @@ static bool DebuginfoCheckPolkit(int uid) //parent int status; - if (waitpid(child_pid, &status, 0) > 0 && WEXITSTATUS(status) == 0) - { + if (waitpid(child_pid, &status, 0) > 0 + && WIFEXITED(status) + && WEXITSTATUS(status) == 0 + ) { return true; //authorization OK } log("UID %d is not authorized to install debuginfos", uid); diff --git a/lib/Plugins/Kerneloops.conf b/lib/Plugins/Kerneloops.conf index 5623596..1db2436 100644 --- a/lib/Plugins/Kerneloops.conf +++ b/lib/Plugins/Kerneloops.conf @@ -15,3 +15,4 @@ SysLogFile = /var/log/messages # KerneloopsReporter configuration ################################## SubmitURL = http://submit.kerneloops.org/submitoops.php +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/KerneloopsScanner.cpp b/lib/Plugins/KerneloopsScanner.cpp index 128e083..1bb45ab 100644 --- a/lib/Plugins/KerneloopsScanner.cpp +++ b/lib/Plugins/KerneloopsScanner.cpp @@ -99,13 +99,14 @@ void CKerneloopsScanner::SaveOopsToDebugDump() *second_line++ = '\0'; try { - CDebugDump debugDump; - debugDump.Create(path, 0); - debugDump.SaveText(FILENAME_ANALYZER, "Kerneloops"); - debugDump.SaveText(FILENAME_EXECUTABLE, "kernel"); - debugDump.SaveText(FILENAME_KERNEL, first_line); - debugDump.SaveText(FILENAME_PACKAGE, "not_applicable"); - debugDump.SaveText(FILENAME_KERNELOOPS, second_line); + CDebugDump dd; + dd.Create(path, 0); + dd.SaveText(FILENAME_ANALYZER, "Kerneloops"); + dd.SaveText(FILENAME_EXECUTABLE, "kernel"); + dd.SaveText(FILENAME_KERNEL, first_line); + dd.SaveText(FILENAME_PACKAGE, "not_applicable"); + dd.SaveText(FILENAME_CMDLINE, "not_applicable"); + dd.SaveText(FILENAME_KERNELOOPS, second_line); } catch (CABRTException& e) { @@ -121,7 +122,7 @@ int CKerneloopsScanner::ScanDmesg() int cnt_FoundOopses; char *buffer; - int pagesz = getpagesize(); + long pagesz = sysconf(_SC_PAGESIZE); buffer = (char*)xzalloc(pagesz + 1); @@ -147,8 +148,10 @@ int CKerneloopsScanner::ScanSysLogFile(const char *filename) if (fd < 0) return 0; statb.st_size = 0; /* paranoia */ - if (fstat(fd, &statb) != 0 || statb.st_size < 1) + if (fstat(fd, &statb) != 0 || statb.st_size < 1) { + close(fd); return 0; + } /* * in theory there's a race here, since someone could spew diff --git a/lib/Plugins/Logger.conf b/lib/Plugins/Logger.conf index 901b3cf..39ba47e 100644 --- a/lib/Plugins/Logger.conf +++ b/lib/Plugins/Logger.conf @@ -2,4 +2,5 @@ LogPath = /var/log/abrt-logger -AppendLogs = yes
\ No newline at end of file +AppendLogs = yes +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Mailx.conf b/lib/Plugins/Mailx.conf index 44c1d18..de19709 100644 --- a/lib/Plugins/Mailx.conf +++ b/lib/Plugins/Mailx.conf @@ -13,3 +13,4 @@ EmailTo = root@localhost # Warning! enabling this may cause sending a lot of MB via email SendBinaryData = no +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp index 70eddb8..df33e84 100644 --- a/lib/Plugins/Mailx.cpp +++ b/lib/Plugins/Mailx.cpp @@ -39,33 +39,16 @@ CMailx::CMailx() : static void exec_and_feed_input(uid_t uid, const char* pText, char **pArgs) { int pipein[2]; - pid_t child; - xpipe(pipein); - child = fork(); - if (child == -1) - { - close(pipein[0]); - close(pipein[1]); - throw CABRTException(EXCEP_PLUGIN, "Can't fork"); - } - if (child == 0) - { - close(pipein[1]); - xmove_fd(pipein[0], STDIN_FILENO); - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - - execvp(pArgs[0], pArgs); - exit(1); /* exec failed */ - } + pid_t child = fork_execv_on_steroids( + EXECFLG_INPUT | EXECFLG_QUIET | EXECFLG_SETGUID, + pArgs, + pipein, + /*unsetenv_vec:*/ NULL, + /*dir:*/ NULL, + uid); - close(pipein[0]); - safe_write(pipein[1], pText, strlen(pText)); + full_write(pipein[1], pText, strlen(pText)); close(pipein[1]); waitpid(child, NULL, 0); /* wait for command completion */ diff --git a/lib/Plugins/Makefile.am b/lib/Plugins/Makefile.am index 2e5ee38..df35416 100644 --- a/lib/Plugins/Makefile.am +++ b/lib/Plugins/Makefile.am @@ -32,7 +32,8 @@ dist_pluginsconf_DATA = \ Bugzilla.conf \ Catcut.conf \ TicketUploader.conf \ - FileTransfer.conf + FileTransfer.conf \ + Python.conf man_MANS = abrt-FileTransfer.7 abrt-Bugzilla.7 abrt-KerneloopsReporter.7 \ abrt-KerneloopsScanner.7 abrt-Logger.7 abrt-Mailx.7 abrt-plugins.7 \ @@ -51,14 +52,13 @@ install-data-hook: $(DESTDIR)/$(DEBUG_INFO_DIR) $(DESTDIR)$(sysconfdir)/abrt/plugins/Logger.conf # CCpp -libCCpp_la_SOURCES = CCpp.cpp CCpp.h +libCCpp_la_SOURCES = CCpp.cpp CCpp.h CCpp_sha1.cpp CCpp_sha1.h libCCpp_la_LDFLAGS = -avoid-version -libCCpp_la_LIBADD = $(NSS_LIBS) +#libCCpp_la_LIBADD = libCCpp_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils \ -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DLOCALSTATEDIR='"$(localstatedir)"' \ - $(NSS_CFLAGS) + -DLOCALSTATEDIR='"$(localstatedir)"' # Firefox - disabled for now @@ -133,7 +133,7 @@ libTicketUploader_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils $(CUR libPython_la_SOURCES = Python.h Python.cpp #libPython_la_LIBADD = $(NSS_LIBS) libPython_la_LDFLAGS = -avoid-version -libPython_la_CPPFLAGS = $(NSS_CFLAGS) -I$(srcdir)/../../inc -I$(srcdir)/../Utils +libPython_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils # FileTrasfer libFileTransfer_la_SOURCES = FileTransfer.cpp FileTransfer.h diff --git a/lib/Plugins/Python.conf b/lib/Plugins/Python.conf new file mode 100644 index 0000000..75d2229 --- /dev/null +++ b/lib/Plugins/Python.conf @@ -0,0 +1 @@ +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/RunApp.cpp b/lib/Plugins/RunApp.cpp index f7cbc01..e2147e2 100644 --- a/lib/Plugins/RunApp.cpp +++ b/lib/Plugins/RunApp.cpp @@ -33,50 +33,38 @@ using namespace std; void CActionRunApp::Run(const char *pActionDir, const char *pArgs) { - /* Don't update_client() - actions run at crash time */ + /* Don't update_client() - actions run at crash time, there is no client + * to talk to at that point */ log("RunApp('%s','%s')", pActionDir, pArgs); vector_string_t args; parse_args(pArgs, args, '"'); + if (args.size() <= COMMAND) + { + return; + } const char *cmd = args[COMMAND].c_str(); if (!cmd[0]) { return; } -//FIXME: need to be able to escape " in .conf - /* Chdir to the dump dir. Command can analyze component and such. + /* NB: we chdir to the dump dir. Command can analyze component and such. * Example: * test x"`cat component`" = x"xorg-x11-apps" && cp /var/log/Xorg.0.log . */ -//Can do it using chdir() in child if we'd open-code popen - string cd_and_cmd = ssprintf("cd '%s'; %s", pActionDir, cmd); - VERB1 log("RunApp: executing '%s'", cd_and_cmd.c_str()); - FILE *fp = popen(cd_and_cmd.c_str(), "r"); - if (fp == NULL) - { - /* Happens only on resource starvation (fork fails or out-of-mem) */ - return; - } - -//FIXME: RunApp("gzip -9 </var/log/Xorg.0.log", "Xorg.0.log.gz") fails -//since we mangle NULs. - string output; - char line[1024]; - while (fgets(line, 1024, fp) != NULL) - { - if (args.size() > FILENAME) - output += line; - } - pclose(fp); + size_t cmd_out_size; + char *cmd_out = run_in_shell_and_save_output(/*flags:*/ 0, cmd, pActionDir, &cmd_out_size); if (args.size() > FILENAME) { CDebugDump dd; dd.Open(pActionDir); - dd.SaveText(args[FILENAME].c_str(), output.c_str()); + dd.SaveBinary(args[FILENAME].c_str(), cmd_out, cmd_out_size); } + + free(cmd_out); } PLUGIN_INFO(ACTION, diff --git a/lib/Plugins/SOSreport.cpp b/lib/Plugins/SOSreport.cpp index 6f23165..2576910 100644 --- a/lib/Plugins/SOSreport.cpp +++ b/lib/Plugins/SOSreport.cpp @@ -91,7 +91,9 @@ void CActionSOSreport::Run(const char *pActionDir, const char *pArgs) update_client(_("running sosreport: %s"), command.c_str()); std::string output = command; output += '\n'; - output += popen_and_save_output(command.c_str()); + char *command_out = run_in_shell_and_save_output(/*flags:*/ 0, command.c_str(), /*dir:*/ NULL, /*size_p:*/ NULL); + output += command_out; + free(command_out); update_client(_("done running sosreport")); std::string sosreport_filename = ParseFilename(output); @@ -101,8 +103,9 @@ void CActionSOSreport::Run(const char *pActionDir, const char *pArgs) dd.Open(pActionDir); //Not useful //dd.SaveText("sosreportoutput", output); - if (copy_file(sosreport_filename.c_str(), sosreport_dd_filename.c_str()) < 0) + if (copy_file(sosreport_filename.c_str(), sosreport_dd_filename.c_str(), 0644) < 0) { + dd.Close(); throw CABRTException(EXCEP_PLUGIN, "Can't copy '%s' to '%s'", sosreport_filename.c_str(), diff --git a/lib/Plugins/SQLite3.conf b/lib/Plugins/SQLite3.conf index 3773c8f..2053642 100644 --- a/lib/Plugins/SQLite3.conf +++ b/lib/Plugins/SQLite3.conf @@ -1,3 +1,4 @@ # Configuration file for database plugin SQLite3 + # DB path DBPath = /var/cache/abrt/abrt-db diff --git a/lib/Plugins/SQLite3.cpp b/lib/Plugins/SQLite3.cpp index 1979f24..ffcf05f 100644 --- a/lib/Plugins/SQLite3.cpp +++ b/lib/Plugins/SQLite3.cpp @@ -90,6 +90,26 @@ static const char *const upate_sql_commands[][ABRT_TABLE_VERSION + 1] = { }, }; + +/* Is this string safe wrt SQL injection? + * PHP's mysql_real_escape_string() treats \, ', ", \x00, \n, \r, and \x1a as special. + * We are a bit more paranoid and disallow any control chars. + */ +static bool is_string_safe(const char *str) +{ + const char *p = str; + while (*p) + { + if ((unsigned char)(*p) < ' ' || strchr("\\\"\'", *p)) + { + error_msg("Probable SQL injection: '%s'", str); + return false; + } + p++; + } + return true; +} + static void get_table(vector_database_rows_t& pTable, sqlite3 *db, const char *fmt, ...) { @@ -308,6 +328,14 @@ void CSQLite3::Insert_or_Update(const char *pUUID, const char *pDebugDumpPath, const char *pTime) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + || !is_string_safe(pDebugDumpPath) + || !is_string_safe(pTime) + ) { + return; + } + if (!exists_uuid_uid(m_pDB, pUUID, pUID)) { execute_sql(m_pDB, @@ -336,20 +364,26 @@ void CSQLite3::Insert_or_Update(const char *pUUID, void CSQLite3::DeleteRow(const char *pUUID, const char *pUID) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + ) { + return; + } + if (pUID[0] == '0' && !pUID[1]) { execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " "WHERE "COL_UUID" = '%s';", - pUUID, pUID + pUUID ); } else if (exists_uuid_uid(m_pDB, pUUID, pUID)) { execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " - "WHERE "COL_UUID" = '%s' " - "AND ("COL_UID" = '%s' OR "COL_UID" = '-1');", - pUUID, pUID + "WHERE "COL_UUID" = '%s' " + "AND ("COL_UID" = '%s' OR "COL_UID" = '-1');", + pUUID, pUID ); } else @@ -360,6 +394,11 @@ void CSQLite3::DeleteRow(const char *pUUID, const char *pUID) void CSQLite3::DeleteRows_by_dir(const char *dump_dir) { + if (!is_string_safe(dump_dir)) + { + return; + } + execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " "WHERE "COL_DEBUG_DUMP_PATH" = '%s'", @@ -369,6 +408,13 @@ void CSQLite3::DeleteRows_by_dir(const char *dump_dir) void CSQLite3::SetReported(const char *pUUID, const char *pUID, const char *pMessage) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + || !is_string_safe(pMessage) + ) { + return; + } + if (pUID[0] == '0' && !pUID[1]) { execute_sql(m_pDB, @@ -409,6 +455,12 @@ void CSQLite3::SetReported(const char *pUUID, const char *pUID, const char *pMes vector_database_rows_t CSQLite3::GetUIDData(const char *pUID) { vector_database_rows_t table; + + if (!is_string_safe(pUID)) + { + return table; + } + if (pUID[0] == '0' && !pUID[1]) { get_table(table, m_pDB, "SELECT * FROM "ABRT_TABLE";"); @@ -426,6 +478,12 @@ vector_database_rows_t CSQLite3::GetUIDData(const char *pUID) database_row_t CSQLite3::GetRow(const char *pUUID, const char *pUID) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + ) { + return database_row_t(); + } + vector_database_rows_t table; if (pUID[0] == '0' && !pUID[1]) diff --git a/lib/Plugins/TicketUploader.cpp b/lib/Plugins/TicketUploader.cpp index a4fe0e8..608ee40 100644 --- a/lib/Plugins/TicketUploader.cpp +++ b/lib/Plugins/TicketUploader.cpp @@ -120,17 +120,14 @@ void CTicketUploader::SendFile(const char *pURL, const char *pFilename) throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename); } struct stat buf; - if (fstat(fileno(f), &buf) == -1) /* TODO: never fails */ - { - throw CABRTException(EXCEP_PLUGIN, "Can't stat archive file '%s'", pFilename); - } + fstat(fileno(f), &buf); /* never fails */ CURL* curl = xcurl_easy_init(); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* specify target */ curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str()); curl_easy_setopt(curl, CURLOPT_READDATA, f); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size); /* everything is done here; result 0 means success */ result = curl_easy_perform(curl); /* goodbye */ @@ -221,7 +218,7 @@ string CTicketUploader::Report(const map_crash_report_t& pCrashReport, else if (it->second[CD_TYPE] == CD_BIN) { string ofile_name = concat_path_file(tmptar_name.c_str(), it->first.c_str()); - if (copy_file(it->second[CD_CONTENT].c_str(), ofile_name.c_str()) < 0) + if (copy_file(it->second[CD_CONTENT].c_str(), ofile_name.c_str(), 0644) < 0) { throw CABRTException(EXCEP_PLUGIN, "Can't copy '%s' to '%s'", @@ -399,19 +396,18 @@ void CTicketUploader::SetSettings(const map_plugin_settings_t& pSettings) } } -//ok to delete? -//const map_plugin_settings_t& CTicketUploader::GetSettings() -//{ -// m_pSettings["Customer"] = m_sCustomer; -// m_pSettings["Ticket"] = m_sTicket; -// m_pSettings["URL"] = m_sURL; -// m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no"; -// m_pSettings["Upload"] = m_bEncrypt ? "yes" : "no"; -// m_pSettings["RetryCount"] = to_string(m_nRetryCount); -// m_pSettings["RetryDelay"] = to_string(m_nRetryDelay); -// -// return m_pSettings; -//} +const map_plugin_settings_t& CTicketUploader::GetSettings() +{ + m_pSettings["Customer"] = m_sCustomer; + m_pSettings["Ticket"] = m_sTicket; + m_pSettings["URL"] = m_sURL; + m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no"; + m_pSettings["Upload"] = m_bEncrypt ? "yes" : "no"; + m_pSettings["RetryCount"] = to_string(m_nRetryCount); + m_pSettings["RetryDelay"] = to_string(m_nRetryDelay); + + return m_pSettings; +} PLUGIN_INFO(REPORTER, CTicketUploader, diff --git a/lib/Plugins/TicketUploader.h b/lib/Plugins/TicketUploader.h index e00596f..1bc8f6b 100644 --- a/lib/Plugins/TicketUploader.h +++ b/lib/Plugins/TicketUploader.h @@ -27,7 +27,7 @@ #include "Plugin.h" #include "Reporter.h" -#include "CrashTypes.h" +//#include "CrashTypes.h" class CTicketUploader : public CReporter { @@ -45,8 +45,7 @@ class CTicketUploader : public CReporter public: CTicketUploader(); virtual ~CTicketUploader(); -//ok to delete? -// virtual const map_plugin_settings_t& GetSettings(); + virtual const map_plugin_settings_t& GetSettings(); virtual void SetSettings(const map_plugin_settings_t& pSettings); virtual std::string Report(const map_crash_report_t& pCrashReport, diff --git a/lib/Utils/CommLayerInner.cpp b/lib/Utils/CommLayerInner.cpp index 133e97d..4a3b80a 100644 --- a/lib/Utils/CommLayerInner.cpp +++ b/lib/Utils/CommLayerInner.cpp @@ -68,11 +68,9 @@ void update_client(const char *fmt, ...) va_list p; va_start(p, fmt); - char *msg; - int used = vasprintf(&msg, fmt, p); + char *msg = xvasprintf(fmt, p); va_end(p); - if (used < 0) - return; s_pObs->Status(msg, peer, key); + free(msg); } diff --git a/lib/Utils/DebugDump.cpp b/lib/Utils/DebugDump.cpp index b4c3ee4..a0a52ab 100644 --- a/lib/Utils/DebugDump.cpp +++ b/lib/Utils/DebugDump.cpp @@ -65,7 +65,9 @@ CDebugDump::CDebugDump() : m_sDebugDumpDir(""), m_pGetNextFileDir(NULL), m_bOpened(false), - m_bLocked(false) + m_bLocked(false), + m_uid(0), + m_gid(0) {} CDebugDump::~CDebugDump() @@ -97,6 +99,15 @@ void CDebugDump::Open(const char *pDir) } Lock(); m_bOpened = true; + /* In case caller would want to create more files, he'll need uid:gid */ + m_uid = 0; + m_gid = 0; + struct stat stat_buf; + if (stat(m_sDebugDumpDir.c_str(), &stat_buf) == 0) + { + m_uid = stat_buf.st_uid; + m_gid = stat_buf.st_gid; + } } bool CDebugDump::Exist(const char* pPath) @@ -115,7 +126,15 @@ static bool GetAndSetLock(const char* pLockFile, const char* pPID) char pid_buf[sizeof(pid_t)*3 + 4]; ssize_t r = readlink(pLockFile, pid_buf, sizeof(pid_buf) - 1); if (r < 0) + { + if (errno == ENOENT) + { + /* Looks like pLockFile was deleted */ + usleep(10 * 1000); /* avoid CPU eating loop */ + continue; + } perror_msg_and_die("Can't read lock file '%s'", pLockFile); + } pid_buf[r] = '\0'; if (strcmp(pid_buf, pPID) == 0) @@ -209,8 +228,8 @@ void CDebugDump::Lock() error_msg_and_die("Locking bug on '%s'", m_sDebugDumpDir.c_str()); std::string lockFile = m_sDebugDumpDir + ".lock"; - char pid_buf[sizeof(int)*3 + 2]; - sprintf(pid_buf, "%u", (unsigned)getpid()); + char pid_buf[sizeof(long)*3 + 2]; + sprintf(pid_buf, "%lu", (long)getpid()); while ((m_bLocked = GetAndSetLock(lockFile.c_str(), pid_buf)) != true) { sleep(1); /* was 0.5 seconds */ @@ -228,7 +247,26 @@ void CDebugDump::UnLock() } } -void CDebugDump::Create(const char *pDir, int64_t uid) +/* Create a fresh empty debug dump dir. + * + * Security: we should not allow users to write new files or write + * into existing ones, but they should be able to read them. + * + * @param uid + * Crashed application's User Id + * + * We currently have only three callers: + * kernel oops hook: uid=0 + * this hook runs under 0:0 + * ccpp hook: uid=uid of crashed user's binary + * this hook runs under 0:0 + * python hook: uid=uid of crashed user's script + * this hook runs under abrt:gid + * + * Currently, we set dir's gid to passwd(uid)->pw_gid parameter, and we set uid to + * abrt's user id. We do not allow write access to group. + */ +void CDebugDump::Create(const char *pDir, uid_t uid) { if (m_bOpened) { @@ -244,25 +282,45 @@ void CDebugDump::Create(const char *pDir, int64_t uid) Lock(); m_bOpened = true; - if (mkdir(m_sDebugDumpDir.c_str(), 0700) == -1) + /* Was creating it with mode 0700 and user as the owner, but this allows + * the user to replace any file in the directory, changing security-sensitive data + * (e.g. "uid", "analyzer", "executable") + */ + if (mkdir(m_sDebugDumpDir.c_str(), 0750) == -1) { UnLock(); m_bOpened = false; throw CABRTException(EXCEP_DD_OPEN, "Can't create dir '%s'", pDir); } - if (chmod(m_sDebugDumpDir.c_str(), 0700) == -1) + + /* mkdir's mode (above) can be affected by umask, fix it */ + if (chmod(m_sDebugDumpDir.c_str(), 0750) == -1) { UnLock(); m_bOpened = false; throw CABRTException(EXCEP_DD_OPEN, "Can't change mode of '%s'", pDir); } - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - if (chown(m_sDebugDumpDir.c_str(), uid, gid) == -1) + + /* Get ABRT's user id */ + m_uid = 0; + struct passwd *pw = getpwnam("abrt"); + if (pw) + m_uid = pw->pw_uid; + else + error_msg("User 'abrt' does not exist, using uid 0"); + + /* Get crashed application's group id */ + m_gid = 0; + pw = getpwuid(uid); + if (pw) + m_gid = pw->pw_gid; + else + error_msg("User %lu does not exist, using gid 0", (long)uid); + + if (chown(m_sDebugDumpDir.c_str(), m_uid, m_gid) == -1) { - /* if /var/cache/abrt is writable by all, _aborting_ here is not useful */ - /* let's just warn */ - perror_msg("can't change '%s' ownership to %u:%u", m_sDebugDumpDir.c_str(), (int)uid, (int)gid); + perror_msg("can't change '%s' ownership to %lu:%lu", m_sDebugDumpDir.c_str(), + (long)m_uid, (long)m_gid); } SaveText(FILENAME_UID, to_string(uid).c_str()); @@ -294,7 +352,7 @@ static void DeleteFileDir(const char *pDir) } } closedir(dir); - if (remove(pDir) == -1) + if (rmdir(pDir) == -1) { throw CABRTException(EXCEP_DD_DELETE, "Can't remove dir %s", pDir); } @@ -359,12 +417,18 @@ static void LoadTextFile(const char *pPath, std::string& pData) fclose(fp); } -static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize) +static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize, uid_t uid, gid_t gid) { - int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0666); + /* "Why 0640?!" See ::Create() for security analysis */ + unlink(pPath); + int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0640); if (fd < 0) { - throw CABRTException(EXCEP_DD_SAVE, "Can't open file '%s'", pPath); + throw CABRTException(EXCEP_DD_SAVE, "Can't open file '%s': %s", pPath, errno ? strerror(errno) : "errno == 0"); + } + if (fchown(fd, uid, gid) == -1) + { + perror_msg("can't change '%s' ownership to %lu:%lu", pPath, (long)uid, (long)gid); } unsigned r = full_write(fd, pData, pSize); close(fd); @@ -391,8 +455,9 @@ void CDebugDump::SaveText(const char* pName, const char* pData) throw CABRTException(EXCEP_DD_OPEN, "DebugDump is not opened"); } std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); - SaveBinaryFile(fullPath.c_str(), pData, strlen(pData)); + SaveBinaryFile(fullPath.c_str(), pData, strlen(pData), m_uid, m_gid); } + void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize) { if (!m_bOpened) @@ -400,7 +465,7 @@ void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize throw CABRTException(EXCEP_DD_OPEN, "DebugDump is not opened"); } std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); - SaveBinaryFile(fullPath.c_str(), pData, pSize); + SaveBinaryFile(fullPath.c_str(), pData, pSize, m_uid, m_gid); } void CDebugDump::InitGetNextFile() diff --git a/lib/Utils/DebugDump.h b/lib/Utils/DebugDump.h index c59552e..d3eebb4 100644 --- a/lib/Utils/DebugDump.h +++ b/lib/Utils/DebugDump.h @@ -51,6 +51,8 @@ class CDebugDump DIR* m_pGetNextFileDir; bool m_bOpened; bool m_bLocked; + uid_t m_uid; + gid_t m_gid; void SaveKernelArchitectureRelease(); @@ -62,7 +64,7 @@ class CDebugDump ~CDebugDump(); void Open(const char *pDir); - void Create(const char *pDir, int64_t uid); + void Create(const char *pDir, uid_t uid); void Delete(); void Close(); diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am index d5e9d98..a944d97 100644 --- a/lib/Utils/Makefile.am +++ b/lib/Utils/Makefile.am @@ -16,7 +16,7 @@ libABRTUtils_la_SOURCES = \ daemon.cpp \ skip_whitespace.cpp \ xatonum.cpp \ - popen_and_save_output.cpp \ + spawn.cpp \ stringops.cpp \ dirsize.cpp \ DebugDump.h DebugDump.cpp \ diff --git a/lib/Utils/Polkit.cpp b/lib/Utils/Polkit.cpp index c868e1a..a7e4a5d 100644 --- a/lib/Utils/Polkit.cpp +++ b/lib/Utils/Polkit.cpp @@ -46,14 +46,12 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) GCancellable * cancellable; authority = polkit_authority_get(); - cancellable = g_cancellable_new(); - g_timeout_add(POLKIT_TIMEOUT * 1000, + guint cancel_timeout = g_timeout_add(POLKIT_TIMEOUT * 1000, (GSourceFunc) do_cancel, cancellable); - result = polkit_authority_check_authorization_sync(authority, subject, action_id, @@ -61,7 +59,8 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, cancellable, &error); - + g_object_unref(authority); + g_source_remove(cancel_timeout); if (error) { g_error_free(error); @@ -71,11 +70,18 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) if (result) { if (polkit_authorization_result_get_is_challenge(result)) + { /* Can't happen (happens only with * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */ + g_object_unref(result); return PolkitChallenge; + } if (polkit_authorization_result_get_is_authorized(result)) + { + g_object_unref(result); return PolkitYes; + } + g_object_unref(result); return PolkitNo; } diff --git a/lib/Utils/abrt_dbus.h b/lib/Utils/abrt_dbus.h index bc9889a..25e099e 100644 --- a/lib/Utils/abrt_dbus.h +++ b/lib/Utils/abrt_dbus.h @@ -154,6 +154,9 @@ enum { ABRT_DBUS_ERROR = -1, ABRT_DBUS_LAST_FIELD = 0, ABRT_DBUS_MORE_FIELDS = 1, + /* note that dbus_message_iter_next() returns FALSE on last field + * and TRUE if there are more fields. + * It maps exactly on the above constants. */ }; /* Checks type, loads data, advances to the next arg. * Returns TRUE if next arg exists. diff --git a/lib/Utils/abrt_xmlrpc.cpp b/lib/Utils/abrt_xmlrpc.cpp index ae1d098..e3a4648 100644 --- a/lib/Utils/abrt_xmlrpc.cpp +++ b/lib/Utils/abrt_xmlrpc.cpp @@ -15,6 +15,16 @@ CURL* xcurl_easy_init() return curl; } +#if 1 +void throw_xml_fault(xmlrpc_env *env) +{ + std::string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env->fault_string, env->fault_code); + xmlrpc_env_clean(env); // this is needed ONLY if fault_occurred + xmlrpc_env_init(env); // just in case user catches ex and _continues_ to use env + error_msg("%s", errmsg.c_str()); // show error in daemon log + throw CABRTException(EXCEP_PLUGIN, errmsg.c_str()); +} +#else void throw_if_xml_fault_occurred(xmlrpc_env *env) { if (env->fault_occurred) @@ -26,6 +36,7 @@ void throw_if_xml_fault_occurred(xmlrpc_env *env) throw CABRTException(EXCEP_PLUGIN, errmsg.c_str()); } } +#endif void abrt_xmlrpc_conn::new_xmlrpc_client(const char* url, bool no_ssl_verify) { @@ -60,15 +71,16 @@ void abrt_xmlrpc_conn::new_xmlrpc_client(const char* url, bool no_ssl_verify) PACKAGE_NAME, VERSION, &clientParms, XMLRPC_CPSIZE(transportparm_size), &m_pClient); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); m_pServer_info = xmlrpc_server_info_new(&env, url); if (env.fault_occurred) { xmlrpc_client_destroy(m_pClient); m_pClient = NULL; + throw_xml_fault(&env); } - throw_if_xml_fault_occurred(&env); } void abrt_xmlrpc_conn::destroy_xmlrpc_client() diff --git a/lib/Utils/abrt_xmlrpc.h b/lib/Utils/abrt_xmlrpc.h index 352e80c..a8bd2cc 100644 --- a/lib/Utils/abrt_xmlrpc.h +++ b/lib/Utils/abrt_xmlrpc.h @@ -24,7 +24,7 @@ struct abrt_xmlrpc_conn { }; /* Utility functions */ -void throw_if_xml_fault_occurred(xmlrpc_env *env); +void throw_xml_fault(xmlrpc_env *env); CURL* xcurl_easy_init(); #endif diff --git a/lib/Utils/copyfd.cpp b/lib/Utils/copyfd.cpp index 9abe752..fdc568a 100644 --- a/lib/Utils/copyfd.cpp +++ b/lib/Utils/copyfd.cpp @@ -106,7 +106,7 @@ off_t copyfd_eof(int fd1, int fd2) return full_fd_action(fd1, fd2, 0); } -off_t copy_file(const char *src_name, const char *dst_name) +off_t copy_file(const char *src_name, const char *dst_name, int mode) { off_t r; int src = open(src_name, O_RDONLY); @@ -115,7 +115,7 @@ off_t copy_file(const char *src_name, const char *dst_name) perror_msg("Can't open '%s'", src_name); return -1; } - int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, 0666); + int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, mode); if (dst < 0) { close(src); diff --git a/lib/Utils/daemon.cpp b/lib/Utils/daemon.cpp index 7aa891c..0527062 100644 --- a/lib/Utils/daemon.cpp +++ b/lib/Utils/daemon.cpp @@ -78,12 +78,12 @@ static char *append_escaped(char *start, const char *s) #define COMMAND_LINE_SIZE 2048 char* get_cmdline(pid_t pid) { - char path[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; + char path[sizeof("/proc/%lu/cmdline") + sizeof(long)*3]; char cmdline[COMMAND_LINE_SIZE]; char escaped_cmdline[COMMAND_LINE_SIZE*4 + 4]; escaped_cmdline[1] = '\0'; - sprintf(path, "/proc/%u/cmdline", (int)pid); + sprintf(path, "/proc/%lu/cmdline", (long)pid); int fd = open(path, O_RDONLY); if (fd >= 0) { diff --git a/lib/Utils/popen_and_save_output.cpp b/lib/Utils/popen_and_save_output.cpp deleted file mode 100644 index 4bcbcac..0000000 --- a/lib/Utils/popen_and_save_output.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Utility routines. - * - * Licensed under GPLv2 or later, see file COPYING in this tarball for details. - */ -#include "abrtlib.h" - -using namespace std; - -string popen_and_save_output(const char *cmd) -{ - string result; - - FILE *fp = popen(cmd, "r"); - if (fp == NULL) /* fork or pipe failed; or out-of-mem */ - { - return result; - } - - size_t sz; - char buf[BUFSIZ + 1]; - while ((sz = fread(buf, 1, sizeof(buf)-1, fp)) > 0) - { - buf[sz] = '\0'; - result += buf; - } - pclose(fp); - - return result; -} diff --git a/lib/Utils/spawn.cpp b/lib/Utils/spawn.cpp new file mode 100644 index 0000000..d3e6ac6 --- /dev/null +++ b/lib/Utils/spawn.cpp @@ -0,0 +1,136 @@ +/* + * Utility routines. + * + * Licensed under GPLv2, see file COPYING in this tarball for details. + */ +#include "abrtlib.h" + +using namespace std; + +static string concat_str_vector(char **strings) +{ + string result; + while (*strings) { + result += *strings++; + if (*strings) + result += ' '; + } + return result; +} + +/* Returns pid */ +pid_t fork_execv_on_steroids(int flags, + char **argv, + int *pipefds, + char **unsetenv_vec, + const char *dir, + uid_t uid) +{ + pid_t child; + /* Reminder: [0] is read end, [1] is write end */ + int pipe_to_child[2]; + int pipe_fm_child[2]; + + /* Sanitize flags */ + if (!pipefds) + flags &= ~(EXECFLG_INPUT | EXECFLG_OUTPUT); + + if (flags & EXECFLG_INPUT) + xpipe(pipe_to_child); + if (flags & EXECFLG_OUTPUT) + xpipe(pipe_fm_child); + + fflush(NULL); + child = fork(); + if (child == -1) { + perror_msg_and_die("fork"); + } + if (child == 0) { + /* Child */ + + /* Play with stdio descriptors */ + if (flags & EXECFLG_INPUT) { + xmove_fd(pipe_to_child[0], STDIN_FILENO); + } else if (flags & EXECFLG_INPUT_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO); + } + if (flags & EXECFLG_OUTPUT) { + xmove_fd(pipe_fm_child[1], STDOUT_FILENO); + } else if (flags & EXECFLG_OUTPUT_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDOUT_FILENO); + } + if (flags & EXECFLG_ERR2OUT) { + /* Want parent to see errors in the same stream */ + xdup2(STDOUT_FILENO, STDERR_FILENO); + } else if (flags & EXECFLG_ERR_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDERR_FILENO); + } + + if (flags & EXECFLG_SETGUID) { + struct passwd* pw = getpwuid(uid); + gid_t gid = pw ? pw->pw_gid : uid; + setgroups(1, &gid); + xsetregid(gid, gid); + xsetreuid(uid, uid); + } + if (flags & EXECFLG_SETSID) + setsid(); + + if (unsetenv_vec) { + while (*unsetenv_vec) + unsetenv(*unsetenv_vec++); + } + + if (dir) + xchdir(dir); + + VERB1 log("Executing: %s", concat_str_vector(argv).c_str()); + execvp(argv[0], argv); + if (!(flags & EXECFLG_QUIET)) + perror_msg("Can't execute '%s'", argv[0]); + exit(127); /* shell uses this exitcode in this case */ + } + + if (flags & EXECFLG_INPUT) { + close(pipe_to_child[0]); + pipefds[1] = pipe_to_child[1]; + } + if (flags & EXECFLG_OUTPUT) { + close(pipe_fm_child[1]); + pipefds[0] = pipe_fm_child[0]; + } + + return child; +} + +char *run_in_shell_and_save_output(int flags, + const char *cmd, + const char *dir, + size_t *size_p) +{ + flags |= EXECFLG_OUTPUT; + flags &= ~EXECFLG_INPUT; + + const char *argv[] = { "/bin/sh", "sh", "-c", cmd, NULL }; + int pipeout[2]; + pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout, + /*unsetenv_vec:*/ NULL, dir, /*uid (unused):*/ 0); + + size_t pos = 0; + char *result = NULL; + while (1) { + result = (char*) xrealloc(result, pos + 4*1024 + 1); + size_t sz = safe_read(pipeout[0], result + pos, 4*1024); + if (sz <= 0) { + break; + } + pos += sz; + } + result[pos] = '\0'; + if (size_p) + *size_p = pos; + close(pipeout[0]); + waitpid(child, NULL, 0); + + return result; +} diff --git a/lib/Utils/xatonum.cpp b/lib/Utils/xatonum.cpp index b096ca8..8314629 100644 --- a/lib/Utils/xatonum.cpp +++ b/lib/Utils/xatonum.cpp @@ -9,7 +9,7 @@ unsigned xatou(const char *numstr) { - unsigned r; + unsigned long r; int old_errno; char *e; @@ -19,7 +19,7 @@ unsigned xatou(const char *numstr) old_errno = errno; errno = 0; r = strtoul(numstr, &e, 10); - if (errno || numstr == e || *e != '\0') + if (errno || numstr == e || *e != '\0' || r > UINT_MAX) goto inval; /* error / no digits / illegal trailing chars */ errno = old_errno; /* Ok. So restore errno. */ return r; diff --git a/lib/Utils/xfuncs.cpp b/lib/Utils/xfuncs.cpp index 8621b5f..f360d33 100644 --- a/lib/Utils/xfuncs.cpp +++ b/lib/Utils/xfuncs.cpp @@ -141,6 +141,12 @@ off_t xlseek(int fd, off_t offset, int whence) return off; } +void xchdir(const char *path) +{ + if (chdir(path)) + perror_msg_and_die("chdir(%s)", path); +} + char* xvasprintf(const char *format, va_list p) { int r; @@ -152,8 +158,8 @@ char* xvasprintf(const char *format, va_list p) #else // Bloat for systems that haven't got the GNU extension. va_list p2; - r = vsnprintf(NULL, 0, format, p); va_copy(p2, p); + r = vsnprintf(NULL, 0, format, p); string_ptr = xmalloc(r+1); r = vsnprintf(string_ptr, r+1, format, p2); va_end(p2); @@ -365,13 +371,13 @@ bool string_to_bool(const char *s) void xsetreuid(uid_t ruid, uid_t euid) { if (setreuid(ruid, euid) != 0) - perror_msg_and_die("can't set %cid %d", 'u', (int)ruid); + perror_msg_and_die("can't set %cid %lu", 'u', (long)ruid); } -void xsetregid(gid_t rgid, uid_t egid) +void xsetregid(gid_t rgid, gid_t egid) { if (setregid(rgid, egid) != 0) - perror_msg_and_die("can't set %cid %d", 'g', (int)rgid); + perror_msg_and_die("can't set %cid %lu", 'g', (long)rgid); } uid_t getuidbyname(const char* login) |
