diff --git a/CMakeLists.txt b/CMakeLists.txt index ee7ef6270..5158a815e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,7 +534,6 @@ set(NEEDED_FUNCTIONS fallocate64 flock getmntent - getpagesize gmtime_r gmtime_s htonll @@ -545,7 +544,6 @@ set(NEEDED_FUNCTIONS ntohll posix_fadvise posix_fallocate - posix_memalign pread pwrite statvfs @@ -553,8 +551,7 @@ set(NEEDED_FUNCTIONS strlcpy strsep syslog - uselocale - valloc) + uselocale) foreach(F ${NEEDED_FUNCTIONS}) tr_make_id("${F}" F_ID) diff --git a/libtransmission/inout.c b/libtransmission/inout.c index af4421439..58be75bad 100644 --- a/libtransmission/inout.c +++ b/libtransmission/inout.c @@ -251,7 +251,7 @@ static bool recalculateHash(tr_torrent* tor, tr_piece_index_t pieceIndex, uint8_ uint32_t offset = 0; bool success = true; size_t const buflen = tor->blockSize; - void* buffer = tr_valloc(buflen); + void* const buffer = tr_malloc(buflen); tr_sha1_ctx_t sha; TR_ASSERT(buffer != NULL); diff --git a/libtransmission/makemeta.c b/libtransmission/makemeta.c index da92e188f..21095c1ed 100644 --- a/libtransmission/makemeta.c +++ b/libtransmission/makemeta.c @@ -265,7 +265,7 @@ static uint8_t* getHashInfo(tr_metainfo_builder* b) return ret; } - buf = tr_valloc(b->pieceSize); + buf = tr_malloc(b->pieceSize); b->pieceIndex = 0; totalRemain = b->totalSize; fd = tr_sys_file_open(b->files[fileIndex].filename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &error); diff --git a/libtransmission/quark.c b/libtransmission/quark.c index b0b1bd8c2..a1cfd9b5c 100644 --- a/libtransmission/quark.c +++ b/libtransmission/quark.c @@ -46,6 +46,8 @@ static struct tr_key_struct const my_static[] = Q("announce"), Q("announce-list"), Q("announceState"), + Q("anti-brute-force-enabled"), + Q("anti-brute-force-threshold"), Q("arguments"), Q("bandwidth-priority"), Q("bandwidthPriority"), diff --git a/libtransmission/quark.h b/libtransmission/quark.h index 45466532c..823543f90 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -45,6 +45,8 @@ enum TR_KEY_announce, /* metainfo */ TR_KEY_announce_list, /* metainfo */ TR_KEY_announceState, /* rpc */ + TR_KEY_anti_brute_force_enabled, /* rpc */ + TR_KEY_anti_brute_force_threshold, /* rpc */ TR_KEY_arguments, /* rpc */ TR_KEY_bandwidth_priority, TR_KEY_bandwidthPriority, diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index d4f6db301..b8b3a6a41 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -65,6 +65,8 @@ struct tr_rpc_server tr_list* whitelist; tr_list* hostWhitelist; int loginattempts; + bool isAntiBruteForceEnabled; + int antiBruteForceThreshold; bool isStreamInitialized; z_stream stream; @@ -641,7 +643,7 @@ static void handle_request(struct evhttp_request* req, void* arg) evhttp_add_header(req->output_headers, "Server", MY_REALM); - if (server->loginattempts == 100) + if (server->isAntiBruteForceEnabled && server->loginattempts >= server->antiBruteForceThreshold) { send_simple_response(req, 403, "

Too many unsuccessful login attempts. Please restart transmission-daemon.

"); return; @@ -681,7 +683,11 @@ static void handle_request(struct evhttp_request* req, void* arg) !tr_ssha1_matches(server->password, pass))) { evhttp_add_header(req->output_headers, "WWW-Authenticate", "Basic realm=\"" MY_REALM "\""); - server->loginattempts++; + if (server->isAntiBruteForceEnabled) + { + server->loginattempts++; + } + char* unauthuser = tr_strdup_printf("

Unauthorized User. %d unsuccessful login attempts.

", server->loginattempts); send_simple_response(req, 401, unauthuser); @@ -1066,6 +1072,30 @@ char const* tr_rpcGetBindAddress(tr_rpc_server const* server) return tr_address_to_string(&server->bindAddress); } +bool tr_rpcGetAntiBruteForceEnabled(tr_rpc_server const* server) +{ + return server->isAntiBruteForceEnabled; +} + +void tr_rpcSetAntiBruteForceEnabled(tr_rpc_server* server, bool isEnabled) +{ + server->isAntiBruteForceEnabled = isEnabled; + if (!isEnabled) + { + server->loginattempts = 0; + } +} + +int tr_rpcGetAntiBruteForceThreshold(tr_rpc_server const* server) +{ + return server->antiBruteForceThreshold; +} + +void tr_rpcSetAntiBruteForceThreshold(tr_rpc_server* server, int badRequests) +{ + server->antiBruteForceThreshold = badRequests; +} + /**** ***** LIFE CYCLE ****/ @@ -1228,6 +1258,28 @@ tr_rpc_server* tr_rpcInit(tr_session* session, tr_variant* settings) tr_rpcSetPassword(s, str); } + key = TR_KEY_anti_brute_force_enabled; + + if (!tr_variantDictFindBool(settings, key, &boolVal)) + { + missing_settings_key(key); + } + else + { + tr_rpcSetAntiBruteForceEnabled(s, boolVal); + } + + key = TR_KEY_anti_brute_force_threshold; + + if (!tr_variantDictFindInt(settings, key, &i)) + { + missing_settings_key(key); + } + else + { + tr_rpcSetAntiBruteForceThreshold(s, i); + } + key = TR_KEY_rpc_bind_address; if (!tr_variantDictFindStr(settings, key, &str, NULL)) diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index ad1eb5204..496359b63 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -58,4 +58,12 @@ void tr_rpcSetPasswordEnabled(tr_rpc_server* server, bool isEnabled); bool tr_rpcIsPasswordEnabled(tr_rpc_server const* session); +bool tr_rpcGetAntiBruteForceEnabled(tr_rpc_server const* server); + +void tr_rpcSetAntiBruteForceEnabled(tr_rpc_server* server, bool is_enabled); + +int tr_rpcGetAntiBruteForceThreshold(tr_rpc_server const* server); + +void tr_rpcSetAntiBruteForceThreshold(tr_rpc_server* server, int badRequests); + char const* tr_rpcGetBindAddress(tr_rpc_server const* server); diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index 1d3a126f3..2772d32b7 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -1676,13 +1676,11 @@ static void gotNewBlocklist(tr_session* session, bool did_connect, bool did_time } else /* successfully fetched the blocklist... */ { - tr_sys_file_t fd; int err; - char* filename; z_stream stream; char const* configDir = tr_sessionGetConfigDir(session); size_t const buflen = 1024 * 128; /* 128 KiB buffer */ - uint8_t* buf = tr_valloc(buflen); + uint8_t* const buf = tr_malloc(buflen); tr_error* error = NULL; /* this is an odd Magic Number required by zlib to enable gz support. @@ -1696,8 +1694,8 @@ static void gotNewBlocklist(tr_session* session, bool did_connect, bool did_time stream.avail_in = response_byte_count; inflateInit2(&stream, windowBits); - filename = tr_buildPath(configDir, "blocklist.tmp.XXXXXX", NULL); - fd = tr_sys_file_open_temp(filename, &error); + char* const filename = tr_buildPath(configDir, "blocklist.tmp.XXXXXX", NULL); + tr_sys_file_t const fd = tr_sys_file_open_temp(filename, &error); if (fd == TR_BAD_SYS_FILE) { @@ -2277,6 +2275,16 @@ static char const* sessionSet(tr_session* session, tr_variant* args_in, tr_varia } } + if (tr_variantDictFindInt(args_in, TR_KEY_anti_brute_force_threshold, &i)) + { + tr_sessionSetAntiBruteForceThreshold(session, i); + } + + if (tr_variantDictFindBool(args_in, TR_KEY_anti_brute_force_enabled, &boolVal)) + { + tr_sessionSetAntiBruteForceEnabled(session, boolVal); + } + notify(session, TR_RPC_SESSION_CHANGED, NULL); return NULL; @@ -2521,6 +2529,14 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key) tr_variantDictAddInt(d, key, tr_sessionGetQueueStalledMinutes(s)); break; + case TR_KEY_anti_brute_force_enabled: + tr_variantDictAddBool(d, key, tr_sessionGetAntiBruteForceEnabled(s)); + break; + + case TR_KEY_anti_brute_force_threshold: + tr_variantDictAddInt(d, key, tr_sessionGetAntiBruteForceThreshold(s)); + break; + case TR_KEY_units: tr_formatter_get_units(tr_variantDictAddDict(d, key, 0)); break; diff --git a/libtransmission/session.c b/libtransmission/session.c index 5ee1001c5..7c2d42041 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -404,6 +404,8 @@ void tr_sessionGetDefaultSettings(tr_variant* d) tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, TR_DEFAULT_BIND_ADDRESS_IPV6); tr_variantDictAddBool(d, TR_KEY_start_added_torrents, true); tr_variantDictAddBool(d, TR_KEY_trash_original_torrent_files, false); + tr_variantDictAddInt(d, TR_KEY_anti_brute_force_threshold, 100); + tr_variantDictAddBool(d, TR_KEY_anti_brute_force_enabled, true); } void tr_sessionGetSettings(tr_session* s, tr_variant* d) @@ -475,6 +477,8 @@ void tr_sessionGetSettings(tr_session* s, tr_variant* d) tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, tr_address_to_string(&s->public_ipv6->addr)); tr_variantDictAddBool(d, TR_KEY_start_added_torrents, !tr_sessionGetPaused(s)); tr_variantDictAddBool(d, TR_KEY_trash_original_torrent_files, tr_sessionGetDeleteSource(s)); + tr_variantDictAddInt(d, TR_KEY_anti_brute_force_threshold, tr_sessionGetAntiBruteForceThreshold(s)); + tr_variantDictAddBool(d, TR_KEY_anti_brute_force_enabled, tr_sessionGetAntiBruteForceEnabled(s)); } bool tr_sessionLoadSettings(tr_variant* dict, char const* configDir, char const* appName) @@ -1144,6 +1148,20 @@ static void sessionSetImpl(void* vdata) session->scrapePausedTorrents = boolVal; } + /** + *** BruteForce + **/ + + if (tr_variantDictFindInt(settings, TR_KEY_anti_brute_force_threshold, &i)) + { + tr_sessionSetAntiBruteForceThreshold(session, i); + } + + if (tr_variantDictFindBool(settings, TR_KEY_anti_brute_force_enabled, &boolVal)) + { + tr_sessionSetAntiBruteForceEnabled(session, boolVal); + } + data->done = true; } @@ -2947,6 +2965,34 @@ int tr_sessionGetQueueStalledMinutes(tr_session const* session) return session->queueStalledMinutes; } +void tr_sessionSetAntiBruteForceThreshold(tr_session* session, int bad_requests) +{ + TR_ASSERT(tr_isSession(session)); + TR_ASSERT(bad_requests > 0); + tr_rpcSetAntiBruteForceThreshold(session->rpcServer, bad_requests); +} + +void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool is_enabled) +{ + TR_ASSERT(tr_isSession(session)); + + tr_rpcSetAntiBruteForceEnabled(session->rpcServer, is_enabled); +} + +bool tr_sessionGetAntiBruteForceEnabled(tr_session const* session) +{ + TR_ASSERT(tr_isSession(session)); + + return tr_rpcGetAntiBruteForceEnabled(session->rpcServer); +} + +int tr_sessionGetAntiBruteForceThreshold(tr_session const* session) +{ + TR_ASSERT(tr_isSession(session)); + + return tr_rpcGetAntiBruteForceThreshold(session->rpcServer); +} + struct TorrentAndPosition { tr_torrent* tor; diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 2dd7a8a7a..35a39a602 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -601,6 +601,15 @@ bool tr_sessionGetDeleteSource(tr_session const*); tr_priority_t tr_torrentGetPriority(tr_torrent const*); void tr_torrentSetPriority(tr_torrent*, tr_priority_t); +void tr_sessionSetAntiBruteForceThreshold(tr_session*, int bad_requests); +int tr_sessionGetAntiBruteForceThreshold(tr_session const*); + +void tr_sessionSetAntiBruteForceEnabled(tr_session*, bool enabled); +bool tr_sessionGetAntiBruteForceEnabled(tr_session const*); + +/** +**/ + /*** **** **** Torrent Queueing diff --git a/libtransmission/utils.c b/libtransmission/utils.c index 5506a6165..8105c3ea9 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -10,11 +10,6 @@ #define _GNU_SOURCE /* glibc's string.h needs this to pick up memmem */ #endif -#if defined(XCODE_BUILD) -#define HAVE_GETPAGESIZE -#define HAVE_VALLOC -#endif - #include /* isdigit(), tolower() */ #include #include /* DBL_DIG */ @@ -554,26 +549,6 @@ int tr_strcmp0(char const* str1, char const* str2) return 0; } -int tr_memcmp0(void const* lhs, void const* rhs, size_t size) -{ - if (lhs != NULL && rhs != NULL) - { - return memcmp(lhs, rhs, size); - } - - if (lhs != NULL) - { - return 1; - } - - if (rhs != NULL) - { - return -1; - } - - return 0; -} - /**** ***** ****/ @@ -1749,7 +1724,7 @@ bool tr_moveFile(char const* oldpath, char const* newpath, tr_error** error) char* buf = NULL; tr_sys_path_info info; uint64_t bytesLeft; - size_t const buflen = 1024 * 1024; /* 1024 KiB buffer */ + size_t const buflen = 1024 * 1024; // 1024 KiB buffer /* make sure the old file exists */ if (!tr_sys_path_get_info(oldpath, 0, &info, error)) @@ -1801,7 +1776,7 @@ bool tr_moveFile(char const* oldpath, char const* newpath, tr_error** error) return false; } - buf = tr_valloc(buflen); + buf = tr_malloc(buflen); bytesLeft = info.size; while (bytesLeft > 0) @@ -1853,58 +1828,6 @@ bool tr_moveFile(char const* oldpath, char const* newpath, tr_error** error) **** ***/ -void* tr_valloc(size_t bufLen) -{ - size_t allocLen; - void* buf = NULL; - static size_t pageSize = 0; - - if (pageSize == 0) - { -#if defined(HAVE_GETPAGESIZE) && !defined(_WIN32) - pageSize = (size_t)getpagesize(); -#else /* guess */ - pageSize = 4096; -#endif - } - - allocLen = pageSize; - - while (allocLen < bufLen) - { - allocLen += pageSize; - } - -#ifdef HAVE_POSIX_MEMALIGN - - if ((buf == NULL) && (posix_memalign(&buf, pageSize, allocLen) != 0)) - { - buf = NULL; /* just retry with valloc/malloc */ - } - -#endif - -#ifdef HAVE_VALLOC - - if (buf == NULL) - { - buf = valloc(allocLen); - } - -#endif - - if (buf == NULL) - { - buf = tr_malloc(allocLen); - } - - return buf; -} - -/*** -**** -***/ - uint64_t tr_htonll(uint64_t x) { #ifdef HAVE_HTONLL diff --git a/libtransmission/utils.h b/libtransmission/utils.h index b4fa62475..da2f0c8cb 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -181,8 +181,6 @@ void* tr_memdup(void const* src, size_t byteCount); ((struct_type*)tr_realloc((mem), sizeof(struct_type) * (size_t)(n_structs))) /* *INDENT-ON* */ -void* tr_valloc(size_t bufLen); - /** * @brief make a newly-allocated copy of a substring * @param in is a void* so that callers can pass in both signed & unsigned without a cast @@ -208,11 +206,6 @@ static inline bool tr_str_is_empty(char const* value) return value == NULL || *value == '\0'; } -/** - * @brief like memcmp() but gracefully handles NULL pointers - */ -int tr_memcmp0(void const* lhs, void const* rhs, size_t size); - char* evbuffer_free_to_str(struct evbuffer* buf, size_t* result_len); /** @brief similar to bsearch() but returns the index of the lower bound */ diff --git a/libtransmission/verify.c b/libtransmission/verify.c index 3bd39215a..630031a1e 100644 --- a/libtransmission/verify.c +++ b/libtransmission/verify.c @@ -18,7 +18,7 @@ #include "platform.h" /* tr_lock() */ #include "torrent.h" #include "tr-assert.h" -#include "utils.h" /* tr_valloc(), tr_free() */ +#include "utils.h" /* tr_malloc(), tr_free() */ #include "verify.h" /*** @@ -32,8 +32,6 @@ enum static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) { - time_t end; - tr_sha1_ctx_t sha; tr_sys_file_t fd = TR_BAD_SYS_FILE; uint64_t filePos = 0; bool changed = false; @@ -44,10 +42,10 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) tr_file_index_t prevFileIndex = !fileIndex; tr_piece_index_t pieceIndex = 0; time_t const begin = tr_time(); - size_t const buflen = 1024 * 128; /* 128 KiB buffer */ - uint8_t* buffer = tr_valloc(buflen); + size_t const buflen = 1024 * 128; // 128 KiB buffer + uint8_t* const buffer = tr_malloc(buflen); - sha = tr_sha1_init(); + tr_sha1_ctx_t sha = tr_sha1_init(); tr_logAddTorDbg(tor, "%s", "verifying torrent..."); tr_torrentSetChecked(tor, 0); @@ -157,7 +155,7 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) free(buffer); /* stopwatch */ - end = tr_time(); + time_t const end = tr_time(); tr_logAddTorDbg(tor, "Verification is done. It took %d seconds to verify %" PRIu64 " bytes (%" PRIu64 " bytes per second)", (int)(end - begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize / (1 + (end - begin)))); diff --git a/qt/ComInteropHelper.cc b/qt/ComInteropHelper.cc index 00550b792..b78513182 100644 --- a/qt/ComInteropHelper.cc +++ b/qt/ComInteropHelper.cc @@ -19,7 +19,7 @@ // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) QAXFACTORY_BEGIN("{1e405fc2-1a3a-468b-8bd6-bfbb58770390}", "{792d1aac-53cc-4dc9-bc29-e5295fdb93a9}") QAXCLASS(InteropObject) -QAXFACTORY_END() +QAXFACTORY_END() // NOLINT // These are ActiveQt internals; declaring here as I don't like their WinMain much... extern HANDLE qAxInstance; // NOLINT diff --git a/tests/libtransmission/rpc-test.cc b/tests/libtransmission/rpc-test.cc index 70e567ce6..613a8efb5 100644 --- a/tests/libtransmission/rpc-test.cc +++ b/tests/libtransmission/rpc-test.cc @@ -102,7 +102,7 @@ TEST_F(RpcTest, sessionGet) EXPECT_TRUE(tr_variantDictFindDict(&response, TR_KEY_arguments, &args)); // what we expected - auto const expected_keys = std::array{ + auto const expected_keys = std::array{ TR_KEY_alt_speed_down, TR_KEY_alt_speed_enabled, TR_KEY_alt_speed_time_begin, @@ -110,6 +110,8 @@ TEST_F(RpcTest, sessionGet) TR_KEY_alt_speed_time_enabled, TR_KEY_alt_speed_time_end, TR_KEY_alt_speed_up, + TR_KEY_anti_brute_force_enabled, + TR_KEY_anti_brute_force_threshold, TR_KEY_blocklist_enabled, TR_KEY_blocklist_size, TR_KEY_blocklist_url,