diff -uNr a/PORTS b/PORTS --- a/PORTS 1970-01-01 00:00:00 +0000 +++ b/PORTS 1970-01-01 00:00:00 +0000 @@ -49,6 +49,7 @@ bc (automake readline) bison (automake m4) libtool (automake) +strace (autoconf automake) sqlite (readline ncurses) sqlite-doc @@ -67,7 +68,7 @@ python-docs 5: -openssh (autoconf libressl zlib) +openssh (autoconf automake libressl zlib) tmux (libevent ncurses) gdb (flex bison readline) sbcl (clisp) diff -uNr a/VERSION b/VERSION --- a/VERSION 1970-01-01 00:00:00 +0000 +++ b/VERSION 1970-01-01 00:00:00 +0000 @@ -1,4 +1,4 @@ -23 +23.1 The major version is the year of release, minus 2000. A new base tarball is published for each major release. diff -uNr a/gports/dovecot/build.sh b/gports/dovecot/build.sh --- a/gports/dovecot/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/dovecot/build.sh 1970-01-01 00:00:00 +0000 @@ -1,13 +1,14 @@ P=dovecot V=2.4.0 MAJOR=0 -MINOR=0 +MINOR=1 # Build requires: flex bison perl # Bundled databases: src/lib/UnicodeData.txt src/lib-fts/WordBreakProperty.txt src/lib-fts/PropList.txt S=" jwrd-dovecot-$V.tar.gz +kill-auth-penalty.patch dovecot.conf run " @@ -20,6 +21,7 @@ root=$PWD/root tar xzf jwrd-dovecot-$V.tar.gz cd jwrd-dovecot-$V + patch -E -p1 < ../kill-auth-penalty.patch # Default CFLAGS include -O1 and no -g. # Security sensitive, so keep low optimization. diff -uNr a/gports/dovecot/dovecot.conf b/gports/dovecot/dovecot.conf --- a/gports/dovecot/dovecot.conf 1970-01-01 00:00:00 +0000 +++ b/gports/dovecot/dovecot.conf 1970-01-01 00:00:00 +0000 @@ -1,5 +1,5 @@ # Basic starting configuration for Dovecot on Gales Linux. -# Some defaults of possible interst are shown commented. There are many more: see `doveconf`. +# Some defaults of possible interest are shown commented. There are many more: see `doveconf`. #default_login_user = dovenull #default_internal_user = dovecot diff -uNr a/gports/dovecot/kill-auth-penalty.patch b/gports/dovecot/kill-auth-penalty.patch --- a/gports/dovecot/kill-auth-penalty.patch 1970-01-01 00:00:00 +0000 +++ b/gports/dovecot/kill-auth-penalty.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,1194 @@ +commit f3f2d74c590e7540e364dfa888065ad54f1a92f3 +Author: Jacob Welsh +AuthorDate: Fri Sep 8 02:38:27 2023 +0000 +Commit: Jacob Welsh +CommitDate: Fri Sep 8 02:45:42 2023 +0000 + + auth, anvil: remove ill-conceived and ill-functioning feature for penalizing failed logins with delayed responses. + + It's an open invitation to denial-of-service attack, especially when used behind a webmail or similar gateway, and the workarounds suggested for supporting that use case are variously broken and ridiculous. + + Some related pieces are not fully removed, search on "penalty" for details, but everything builds. + + http://jfxpt.com/2023/jwrd-logs-for-Sep-2023/#9198 + +diff --git a/src/Makefile b/src/Makefile +index 0776828456..7573d8b387 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -140,7 +140,6 @@ LIBEXEC_PROGS = \ + util/script-login \ + + TEST_PROGS = \ +- anvil/test-penalty \ + auth/test-libpassword \ + auth/test-auth-cache \ + auth/test-auth \ +@@ -626,7 +625,6 @@ LIBDOVECOT_OBJS += \ + auth/auth-client-connection.o \ + auth/auth-fields.o \ + auth/auth-master-connection.o \ +- auth/auth-penalty.o \ + auth/auth-policy.o \ + auth/auth-request-fields.o \ + auth/auth-request-handler.o \ +@@ -1525,10 +1523,8 @@ anvil/anvil: \ + anvil/anvil-connection.o \ + anvil/anvil-settings.o \ + anvil/connect-limit.o \ +- anvil/main.o \ +- anvil/penalty.o ++ anvil/main.o + $(LINK) +-anvil/test-penalty: anvil/test-penalty.o anvil/penalty.o + + auth/auth: auth/main.o + $(LINK) +diff --git a/src/anvil/anvil-connection.c b/src/anvil/anvil-connection.c +index 20e859b5c3..69767add88 100644 +--- a/src/anvil/anvil-connection.c ++++ b/src/anvil/anvil-connection.c +@@ -8,7 +8,6 @@ + #include "master-service.h" + #include "master-interface.h" + #include "connect-limit.h" +-#include "penalty.h" + #include "anvil-connection.h" + + #include +@@ -48,8 +47,7 @@ anvil_connection_request(struct anvil_connection *conn, + const char *const *args, const char **error_r) + { + const char *cmd = args[0]; +- unsigned int value, checksum; +- time_t stamp; ++ unsigned int value; + pid_t pid; + + args++; +@@ -101,36 +99,9 @@ anvil_connection_request(struct anvil_connection *conn, + value = connect_limit_lookup(connect_limit, args[0]); + o_stream_nsend_str(conn->output, + t_strdup_printf("%u\n", value)); +- } else if (strcmp(cmd, "PENALTY-GET") == 0) { +- if (args[0] == NULL) { +- *error_r = "PENALTY-GET: Not enough parameters"; +- return -1; +- } +- value = penalty_get(penalty, args[0], &stamp); +- o_stream_nsend_str(conn->output, +- t_strdup_printf("%u %s\n", value, dec2str(stamp))); +- } else if (strcmp(cmd, "PENALTY-INC") == 0) { +- if (args[0] == NULL || args[1] == NULL || args[2] == NULL) { +- *error_r = "PENALTY-INC: Not enough parameters"; +- return -1; +- } +- if (str_to_uint(args[1], &checksum) < 0 || +- str_to_uint(args[2], &value) < 0 || +- value > PENALTY_MAX_VALUE || +- (value == 0 && checksum != 0)) { +- *error_r = "PENALTY-INC: Invalid parameters"; +- return -1; +- } +- penalty_inc(penalty, args[0], checksum, value); +- } else if (strcmp(cmd, "PENALTY-SET-EXPIRE-SECS") == 0) { +- if (args[0] == NULL || str_to_uint(args[0], &value) < 0) { +- *error_r = "PENALTY-SET-EXPIRE-SECS: " +- "Invalid parameters"; +- return -1; +- } +- penalty_set_expire_secs(penalty, value); + } else if (strcmp(cmd, "PENALTY-DUMP") == 0) { +- penalty_dump(penalty, conn->output); ++ /* Penalty interface removed but 'doveadm penalty' could still query it, so return an empty result. We could perhaps stub out the doveadm command too. */ ++ o_stream_nsend(conn->output, "\n", 1); + } else { + *error_r = t_strconcat("Unknown command: ", cmd, NULL); + return -1; +diff --git a/src/anvil/anvil-settings.c b/src/anvil/anvil-settings.c +index a94823e02f..51529ff449 100644 +--- a/src/anvil/anvil-settings.c ++++ b/src/anvil/anvil-settings.c +@@ -10,11 +10,9 @@ + /* */ + static struct file_listener_settings anvil_unix_listeners_array[] = { + { "anvil", 0600, "", "" }, +- { "anvil-auth-penalty", 0600, "", "" } + }; + static struct file_listener_settings *anvil_unix_listeners[] = { +- &anvil_unix_listeners_array[0], +- &anvil_unix_listeners_array[1] ++ &anvil_unix_listeners_array[0] + }; + static buffer_t anvil_unix_listeners_buf = { + { { anvil_unix_listeners, sizeof(anvil_unix_listeners) } } +diff --git a/src/anvil/common.h b/src/anvil/common.h +index f9a44bd576..4f3b3da1e1 100644 +--- a/src/anvil/common.h ++++ b/src/anvil/common.h +@@ -4,7 +4,6 @@ + #include "lib.h" + + extern struct connect_limit *connect_limit; +-extern struct penalty *penalty; + extern bool anvil_restarted; + + #endif +diff --git a/src/anvil/main.c b/src/anvil/main.c +index 7e4050bc59..8d7cf0cc2f 100644 +--- a/src/anvil/main.c ++++ b/src/anvil/main.c +@@ -10,13 +10,11 @@ + #include "master-service-settings.h" + #include "master-interface.h" + #include "connect-limit.h" +-#include "penalty.h" + #include "anvil-connection.h" + + #include + + struct connect_limit *connect_limit; +-struct penalty *penalty; + bool anvil_restarted; + static struct io *log_fdpass_io; + +@@ -74,7 +72,6 @@ int main(int argc, char *argv[]) + master_service_set_die_with_master(master_service, FALSE); + + connect_limit = connect_limit_init(); +- penalty = penalty_init(); + log_fdpass_io = io_add(MASTER_ANVIL_LOG_FDPASS_FD, IO_READ, + log_fdpass_input, NULL); + master_service_init_finish(master_service); +@@ -82,7 +79,6 @@ int main(int argc, char *argv[]) + master_service_run(master_service, client_connected); + + io_remove(&log_fdpass_io); +- penalty_deinit(&penalty); + connect_limit_deinit(&connect_limit); + anvil_connections_destroy_all(); + master_service_deinit(&master_service); +diff --git a/src/anvil/penalty.c b/src/anvil/penalty.c +deleted file mode 100644 +index 2ab6da16aa..0000000000 +--- a/src/anvil/penalty.c ++++ /dev/null +@@ -1,273 +0,0 @@ +-/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ +- +-/* The idea behind checksums is that the same username+password doesn't +- increase the penalty, because it's most likely a user with a misconfigured +- account. */ +- +-#include "lib.h" +-#include "ioloop.h" +-#include "hash.h" +-#include "str.h" +-#include "strescape.h" +-#include "llist.h" +-#include "ostream.h" +-#include "penalty.h" +- +-#include +- +-#define PENALTY_DEFAULT_EXPIRE_SECS (60*60) +-#define PENALTY_CHECKSUM_SAVE_COUNT +-#define CHECKSUM_VALUE_COUNT 2 +-#define CHECKSUM_VALUE_PTR_COUNT 10 +- +-#define LAST_UPDATE_BITS 15 +- +-struct penalty_rec { +- /* ordered by last_update */ +- struct penalty_rec *prev, *next; +- +- char *ident; +- unsigned int last_penalty; +- +- unsigned int penalty:16; +- unsigned int last_update:LAST_UPDATE_BITS; /* last_penalty + n */ +- bool checksum_is_pointer:1; +- /* we use value up to two different checksums. +- after that switch to pointer. */ +- union { +- unsigned int value[CHECKSUM_VALUE_COUNT]; +- unsigned int *value_ptr; +- } checksum; +-}; +- +-struct penalty { +- /* ident => penalty_rec */ +- HASH_TABLE(char *, struct penalty_rec *) hash; +- struct penalty_rec *oldest, *newest; +- +- unsigned int expire_secs; +- struct timeout *to; +-}; +- +-struct penalty *penalty_init(void) +-{ +- struct penalty *penalty; +- +- penalty = i_new(struct penalty, 1); +- hash_table_create(&penalty->hash, default_pool, 0, str_hash, strcmp); +- penalty->expire_secs = PENALTY_DEFAULT_EXPIRE_SECS; +- return penalty; +-} +- +-static void penalty_rec_free(struct penalty *penalty, struct penalty_rec *rec) +-{ +- DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec); +- if (rec->checksum_is_pointer) +- i_free(rec->checksum.value_ptr); +- i_free(rec->ident); +- i_free(rec); +-} +- +-void penalty_deinit(struct penalty **_penalty) +-{ +- struct penalty *penalty = *_penalty; +- +- *_penalty = NULL; +- +- while (penalty->oldest != NULL) +- penalty_rec_free(penalty, penalty->oldest); +- hash_table_destroy(&penalty->hash); +- +- timeout_remove(&penalty->to); +- i_free(penalty); +-} +- +-void penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs) +-{ +- penalty->expire_secs = expire_secs; +-} +- +-static bool +-penalty_bump_checksum(struct penalty_rec *rec, unsigned int checksum) +-{ +- unsigned int *checksums; +- unsigned int i, count; +- +- if (!rec->checksum_is_pointer) { +- checksums = rec->checksum.value; +- count = CHECKSUM_VALUE_COUNT; +- } else { +- checksums = rec->checksum.value_ptr; +- count = CHECKSUM_VALUE_PTR_COUNT; +- } +- +- for (i = 0; i < count; i++) { +- if (checksums[i] == checksum) { +- if (i > 0) { +- memmove(checksums + 1, checksums, +- sizeof(checksums[0]) * i); +- checksums[0] = checksum; +- } +- return TRUE; +- } +- } +- return FALSE; +-} +- +-static void penalty_add_checksum(struct penalty_rec *rec, unsigned int checksum) +-{ +- unsigned int *checksums; +- +- i_assert(checksum != 0); +- +- if (!rec->checksum_is_pointer) { +- if (rec->checksum.value[CHECKSUM_VALUE_COUNT-1] == 0) { +- memcpy(rec->checksum.value + 1, rec->checksum.value, +- sizeof(rec->checksum.value[0]) * +- (CHECKSUM_VALUE_COUNT-1)); +- rec->checksum.value[0] = checksum; +- return; +- } +- +- /* switch to using a pointer */ +- checksums = i_new(unsigned int, CHECKSUM_VALUE_PTR_COUNT); +- memcpy(checksums, rec->checksum.value, +- sizeof(checksums[0]) * CHECKSUM_VALUE_COUNT); +- rec->checksum.value_ptr = checksums; +- rec->checksum_is_pointer = TRUE; +- } +- +- memmove(rec->checksum.value_ptr + 1, rec->checksum.value_ptr, +- sizeof(rec->checksum.value_ptr[0]) * +- (CHECKSUM_VALUE_PTR_COUNT-1)); +- rec->checksum.value_ptr[0] = checksum; +-} +- +-unsigned int penalty_get(struct penalty *penalty, const char *ident, +- time_t *last_penalty_r) +-{ +- struct penalty_rec *rec; +- +- rec = hash_table_lookup(penalty->hash, ident); +- if (rec == NULL) { +- *last_penalty_r = 0; +- return 0; +- } +- +- *last_penalty_r = rec->last_penalty; +- return rec->penalty; +-} +- +-static void penalty_timeout(struct penalty *penalty) +-{ +- struct penalty_rec *rec; +- time_t rec_last_update, expire_time; +- unsigned int diff; +- +- timeout_remove(&penalty->to); +- +- expire_time = ioloop_time - penalty->expire_secs; +- while (penalty->oldest != NULL) { +- rec = penalty->oldest; +- +- rec_last_update = rec->last_penalty + rec->last_update; +- if (rec_last_update > expire_time) { +- diff = rec_last_update - expire_time; +- penalty->to = timeout_add(diff * 1000, +- penalty_timeout, penalty); +- break; +- } +- hash_table_remove(penalty->hash, rec->ident); +- penalty_rec_free(penalty, rec); +- } +-} +- +-void penalty_inc(struct penalty *penalty, const char *ident, +- unsigned int checksum, unsigned int value) +-{ +- struct penalty_rec *rec; +- time_t diff; +- +- i_assert(value > 0 || checksum == 0); +- i_assert(value <= INT_MAX); +- +- rec = hash_table_lookup(penalty->hash, ident); +- if (rec == NULL) { +- rec = i_new(struct penalty_rec, 1); +- rec->ident = i_strdup(ident); +- hash_table_insert(penalty->hash, rec->ident, rec); +- } else { +- DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec); +- } +- +- if (checksum == 0) { +- rec->penalty = value; +- rec->last_penalty = ioloop_time; +- } else { +- if (penalty_bump_checksum(rec, checksum)) +- rec->penalty = value - 1; +- else { +- penalty_add_checksum(rec, checksum); +- rec->penalty = value; +- rec->last_penalty = ioloop_time; +- } +- } +- +- diff = ioloop_time - rec->last_penalty; +- if (diff >= (1 << LAST_UPDATE_BITS)) { +- rec->last_update = (1 << LAST_UPDATE_BITS) - 1; +- rec->last_penalty = ioloop_time - rec->last_update; +- } else { +- rec->last_update = diff; +- } +- +- DLLIST2_APPEND(&penalty->oldest, &penalty->newest, rec); +- +- if (penalty->to == NULL) { +- penalty->to = timeout_add(penalty->expire_secs * 1000, +- penalty_timeout, penalty); +- } +-} +- +-bool penalty_has_checksum(struct penalty *penalty, const char *ident, +- unsigned int checksum) +-{ +- struct penalty_rec *rec; +- const unsigned int *checksums; +- unsigned int i, count; +- +- rec = hash_table_lookup(penalty->hash, ident); +- if (rec == NULL) +- return FALSE; +- +- if (!rec->checksum_is_pointer) { +- checksums = rec->checksum.value; +- count = CHECKSUM_VALUE_COUNT; +- } else { +- checksums = rec->checksum.value_ptr; +- count = CHECKSUM_VALUE_PTR_COUNT; +- } +- +- for (i = 0; i < count; i++) { +- if (checksums[i] == checksum) +- return TRUE; +- } +- return FALSE; +-} +- +-void penalty_dump(struct penalty *penalty, struct ostream *output) +-{ +- const struct penalty_rec *rec; +- string_t *str = t_str_new(256); +- +- for (rec = penalty->oldest; rec != NULL; rec = rec->next) { +- str_truncate(str, 0); +- str_append_tabescaped(str, rec->ident); +- str_printfa(str, "\t%u\t%u\t%u\n", +- rec->penalty, rec->last_penalty, +- rec->last_penalty + rec->last_update); +- if (o_stream_send(output, str_data(str), str_len(str)) < 0) +- break; +- } +- o_stream_nsend(output, "\n", 1); +-} +diff --git a/src/anvil/penalty.h b/src/anvil/penalty.h +deleted file mode 100644 +index 23a182cde4..0000000000 +--- a/src/anvil/penalty.h ++++ /dev/null +@@ -1,22 +0,0 @@ +-#ifndef PENALTY_H +-#define PENALTY_H +- +-#define PENALTY_MAX_VALUE ((1 << 16)-1) +- +-struct penalty *penalty_init(void); +-void penalty_deinit(struct penalty **penalty); +- +-void penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs); +- +-unsigned int penalty_get(struct penalty *penalty, const char *ident, +- time_t *last_penalty_r); +-/* if checksum is non-zero and it already exists for ident, the value +- is set to "value-1", otherwise it's set to "value". */ +-void penalty_inc(struct penalty *penalty, const char *ident, +- unsigned int checksum, unsigned int value); +- +-bool penalty_has_checksum(struct penalty *penalty, const char *ident, +- unsigned int checksum); +-void penalty_dump(struct penalty *penalty, struct ostream *output); +- +-#endif +diff --git a/src/anvil/test-penalty.c b/src/anvil/test-penalty.c +deleted file mode 100644 +index 438bf9eb0a..0000000000 +--- a/src/anvil/test-penalty.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ +- +-#include "lib.h" +-#include "ioloop.h" +-#include "penalty.h" +-#include "test-common.h" +- +-static void test_penalty_checksum(void) +-{ +- struct penalty *penalty; +- struct ioloop *ioloop; +- time_t t; +- unsigned int i, j; +- +- test_begin("penalty"); +- +- ioloop = io_loop_create(); +- penalty = penalty_init(); +- +- test_assert(penalty_get(penalty, "foo", &t) == 0); +- for (i = 1; i <= 10; i++) { +- ioloop_time = 12345678 + i; +- penalty_inc(penalty, "foo", i, 5+i); +- +- for (j = I_MIN(1, i-1); j <= i; j++) { +- test_assert(penalty_get(penalty, "foo", &t) == 5+i); +- test_assert(t == (time_t)(12345678 + i)); +- test_assert(penalty_has_checksum(penalty, "foo", i)); +- } +- test_assert(penalty_get(penalty, "foo", &t) == 5+i); +- test_assert(t == (time_t)(12345678 + i)); +- test_assert(!penalty_has_checksum(penalty, "foo", j)); +- } +- test_assert(penalty_get(penalty, "foo2", &t) == 0); +- +- /* overflows checksum array */ +- ioloop_time = 12345678 + i; +- penalty_inc(penalty, "foo", i, 5 + i); +- penalty_inc(penalty, "foo", i, 5 + i); +- penalty_inc(penalty, "foo", 0, 5 + i); +- +- test_assert(penalty_get(penalty, "foo", &t) == 5+i); +- test_assert(t == (time_t)(12345678 + i)); +- test_assert(!penalty_has_checksum(penalty, "foo", 1)); +- +- for (j = 2; j <= i; j++) { +- test_assert(penalty_get(penalty, "foo", &t) == 5+i); +- test_assert(t == (time_t)(12345678 + i)); +- test_assert(penalty_has_checksum(penalty, "foo", i)); +- } +- +- penalty_deinit(&penalty); +- io_loop_destroy(&ioloop); +- test_end(); +-} +- +-int main(void) +-{ +- static void (*const test_functions[])(void) = { +- test_penalty_checksum, +- NULL +- }; +- return test_run(test_functions); +-} +diff --git a/src/auth/auth-common.h b/src/auth/auth-common.h +index 5ebe8c489a..75385594b0 100644 +--- a/src/auth/auth-common.h ++++ b/src/auth/auth-common.h +@@ -6,7 +6,6 @@ + + extern bool worker, worker_restart_request; + extern time_t process_start_time; +-extern struct auth_penalty *auth_penalty; + extern struct event_category event_category_auth; + extern struct event *auth_event; + +diff --git a/src/auth/auth-penalty.c b/src/auth/auth-penalty.c +deleted file mode 100644 +index 3816902a0a..0000000000 +--- a/src/auth/auth-penalty.c ++++ /dev/null +@@ -1,176 +0,0 @@ +-/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ +- +-#include "lib.h" +-#include "ioloop.h" +-#include "net.h" +-#include "crc32.h" +-#include "master-service.h" +-#include "anvil-client.h" +-#include "auth-request.h" +-#include "auth-penalty.h" +- +-#include +- +-/* We don't want IPv6 hosts being able to flood our penalty +- tracking with tons of different IPs. */ +-#define PENALTY_IPV6_MASK_BITS 48 +- +-struct auth_penalty_request { +- struct auth_request *auth_request; +- struct anvil_client *client; +- auth_penalty_callback_t *callback; +-}; +- +-struct auth_penalty { +- struct anvil_client *client; +- +- bool disabled:1; +-}; +- +-struct auth_penalty *auth_penalty_init(const char *path) +-{ +- struct auth_penalty *penalty; +- +- penalty = i_new(struct auth_penalty, 1); +- penalty->client = anvil_client_init(path, NULL, +- ANVIL_CLIENT_FLAG_HIDE_ENOENT); +- if (anvil_client_connect(penalty->client, TRUE) < 0) +- penalty->disabled = TRUE; +- else { +- anvil_client_cmd(penalty->client, t_strdup_printf( +- "PENALTY-SET-EXPIRE-SECS\t%u", AUTH_PENALTY_TIMEOUT)); +- } +- return penalty; +-} +- +-void auth_penalty_deinit(struct auth_penalty **_penalty) +-{ +- struct auth_penalty *penalty = *_penalty; +- +- *_penalty = NULL; +- anvil_client_deinit(&penalty->client); +- i_free(penalty); +-} +- +-unsigned int auth_penalty_to_secs(unsigned int penalty) +-{ +- unsigned int i, secs = AUTH_PENALTY_INIT_SECS; +- +- for (i = 0; i < penalty; i++) +- secs *= 2; +- return secs < AUTH_PENALTY_MAX_SECS ? secs : AUTH_PENALTY_MAX_SECS; +-} +- +-static void auth_penalty_anvil_callback(const char *reply, void *context) +-{ +- struct auth_penalty_request *request = context; +- unsigned int penalty = 0; +- unsigned long last_penalty = 0; +- unsigned int secs, drop_penalty; +- +- if (reply == NULL) { +- /* internal failure. */ +- if (!anvil_client_is_connected(request->client)) { +- /* we probably didn't have permissions to reconnect +- back to anvil. need to restart ourself. */ +- master_service_stop(master_service); +- } +- } else if (sscanf(reply, "%u %lu", &penalty, &last_penalty) != 2) { +- e_error(request->auth_request->event, +- "Invalid PENALTY-GET reply: %s", reply); +- } else { +- if ((time_t)last_penalty > ioloop_time) { +- /* time moved backwards? */ +- last_penalty = ioloop_time; +- } +- +- /* update penalty. */ +- drop_penalty = AUTH_PENALTY_MAX_PENALTY; +- while (penalty > 0) { +- secs = auth_penalty_to_secs(drop_penalty); +- if (ioloop_time - last_penalty < secs) +- break; +- drop_penalty--; +- penalty--; +- } +- } +- +- request->callback(penalty, request->auth_request); +- auth_request_unref(&request->auth_request); +- i_free(request); +-} +- +-static const char * +-auth_penalty_get_ident(struct auth_request *auth_request) +-{ +- struct ip_addr ip; +- +- ip = auth_request->fields.remote_ip; +- if (IPADDR_IS_V6(&ip)) { +- memset(ip.u.ip6.s6_addr + PENALTY_IPV6_MASK_BITS/CHAR_BIT, 0, +- sizeof(ip.u.ip6.s6_addr) - +- PENALTY_IPV6_MASK_BITS/CHAR_BIT); +- } +- return net_ip2addr(&ip); +-} +- +-void auth_penalty_lookup(struct auth_penalty *penalty, +- struct auth_request *auth_request, +- auth_penalty_callback_t *callback) +-{ +- struct auth_penalty_request *request; +- const char *ident; +- +- ident = auth_penalty_get_ident(auth_request); +- if (penalty->disabled || ident == NULL || +- auth_request->fields.no_penalty) { +- callback(0, auth_request); +- return; +- } +- +- request = i_new(struct auth_penalty_request, 1); +- request->auth_request = auth_request; +- request->client = penalty->client; +- request->callback = callback; +- auth_request_ref(auth_request); +- +- T_BEGIN { +- anvil_client_query(penalty->client, +- t_strdup_printf("PENALTY-GET\t%s", ident), +- auth_penalty_anvil_callback, request); +- } T_END; +-} +- +-static unsigned int +-get_userpass_checksum(struct auth_request *auth_request) +-{ +- return auth_request->mech_password == NULL ? 0 : +- crc32_str_more(crc32_str(auth_request->mech_password), +- auth_request->fields.user); +-} +- +-void auth_penalty_update(struct auth_penalty *penalty, +- struct auth_request *auth_request, unsigned int value) +-{ +- const char *ident; +- +- ident = auth_penalty_get_ident(auth_request); +- if (penalty->disabled || ident == NULL || +- auth_request->fields.no_penalty) +- return; +- +- if (value > AUTH_PENALTY_MAX_PENALTY) { +- /* even if the actual value doesn't change, the last_change +- timestamp does. */ +- value = AUTH_PENALTY_MAX_PENALTY; +- } +- T_BEGIN { +- const char *cmd; +- unsigned int checksum; +- +- checksum = value == 0 ? 0 : get_userpass_checksum(auth_request); +- cmd = t_strdup_printf("PENALTY-INC\t%s\t%u\t%u", +- ident, checksum, value); +- anvil_client_cmd(penalty->client, cmd); +- } T_END; +-} +diff --git a/src/auth/auth-penalty.h b/src/auth/auth-penalty.h +deleted file mode 100644 +index 96783e4f58..0000000000 +--- a/src/auth/auth-penalty.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-#ifndef AUTH_PENALTY_H +-#define AUTH_PENALTY_H +- +-struct auth_request; +- +-#define AUTH_PENALTY_INIT_SECS 2 +-#define AUTH_PENALTY_MAX_SECS 15 +-/* timeout specifies how long it takes for penalty to be irrelevant. */ +-#define AUTH_PENALTY_TIMEOUT \ +- (AUTH_PENALTY_INIT_SECS + 4 + 8 + AUTH_PENALTY_MAX_SECS) +-#define AUTH_PENALTY_MAX_PENALTY 4 +- +-/* If lookup failed, penalty and last_update are both zero */ +-typedef void auth_penalty_callback_t(unsigned int penalty, +- struct auth_request *request); +- +-struct auth_penalty *auth_penalty_init(const char *path); +-void auth_penalty_deinit(struct auth_penalty **penalty); +- +-unsigned int auth_penalty_to_secs(unsigned int penalty); +- +-void auth_penalty_lookup(struct auth_penalty *penalty, +- struct auth_request *auth_request, +- auth_penalty_callback_t *callback); +-void auth_penalty_update(struct auth_penalty *penalty, +- struct auth_request *auth_request, unsigned int value); +- +-#endif +diff --git a/src/auth/auth-policy.c b/src/auth/auth-policy.c +index 951f85e6f8..de70b533ab 100644 +--- a/src/auth/auth-policy.c ++++ b/src/auth/auth-policy.c +@@ -14,7 +14,6 @@ + #include "master-service.h" + #include "master-service-ssl-settings.h" + #include "auth-request.h" +-#include "auth-penalty.h" + #include "auth-settings.h" + #include "auth-policy.h" + #include "auth-common.h" +diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c +index d4bf53c276..646766633c 100644 +--- a/src/auth/auth-request-handler.c ++++ b/src/auth/auth-request-handler.c +@@ -2,8 +2,6 @@ + + #include "auth-common.h" + #include "ioloop.h" +-#include "array.h" +-#include "aqueue.h" + #include "base64.h" + #include "hash.h" + #include "net.h" +@@ -11,7 +9,6 @@ + #include "strescape.h" + #include "str-sanitize.h" + #include "master-interface.h" +-#include "auth-penalty.h" + #include "auth-request.h" + #include "auth-token.h" + #include "auth-client-connection.h" +@@ -20,14 +17,6 @@ + #include "auth-request-handler-private.h" + #include "auth-policy.h" + +-#define AUTH_FAILURE_DELAY_CHECK_MSECS 500 +-static ARRAY(struct auth_request *) auth_failures_arr; +-static struct aqueue *auth_failures; +-static struct timeout *to_auth_failures; +- +-static void auth_failure_timeout(void *context) ATTR_NULL(1); +- +- + static void + auth_request_handler_default_reply_callback(struct auth_request *request, + enum auth_client_result result, +@@ -221,12 +210,6 @@ auth_request_handle_failure(struct auth_request *request, const char *reply) + /* handle failure here */ + auth_request_log_finished(request); + +- if (request->in_delayed_failure_queue) { +- /* we came here from flush_failures() */ +- handler->callback(reply, handler->conn); +- return; +- } +- + /* remove the request from requests-list */ + auth_request_ref(request); + auth_request_handler_remove(handler, request); +@@ -234,30 +217,8 @@ auth_request_handle_failure(struct auth_request *request, const char *reply) + if (request->set->policy_report_after_auth) + auth_policy_report(request); + +- if (auth_fields_exists(request->fields.extra_fields, "nodelay")) { +- /* passdb specifically requested not to delay the reply. */ +- handler->callback(reply, handler->conn); +- auth_request_unref(&request); +- return; +- } +- +- /* failure. don't announce it immediately to avoid +- a) timing attacks, b) flooding */ +- request->in_delayed_failure_queue = TRUE; +- handler->refcount++; +- +- if (auth_penalty != NULL) { +- auth_penalty_update(auth_penalty, request, +- request->last_penalty + 1); +- } +- +- auth_request_refresh_last_access(request); +- aqueue_append(auth_failures, &request); +- if (to_auth_failures == NULL) { +- to_auth_failures = +- timeout_add_short(AUTH_FAILURE_DELAY_CHECK_MSECS, +- auth_failure_timeout, NULL); +- } ++ handler->callback(reply, handler->conn); ++ auth_request_unref(&request); + } + + static void +@@ -268,11 +229,6 @@ auth_request_handler_reply_success_finish(struct auth_request *request) + + auth_request_log_finished(request); + +- if (request->last_penalty != 0 && auth_penalty != NULL) { +- /* reset penalty */ +- auth_penalty_update(auth_penalty, request, 0); +- } +- + /* sanitize these fields, since the login code currently assumes they + are exactly in this format. */ + auth_fields_booleanize(request->fields.extra_fields, "nologin"); +@@ -336,11 +292,6 @@ auth_request_handler_reply_failure_finish(struct auth_request *request) + } + } + +- if (auth_fields_exists(request->fields.extra_fields, "nodelay")) { +- /* this is normally a hidden field, need to add it explicitly */ +- str_append(str, "\tnodelay"); +- } +- + if (code != NULL) { + str_append(str, "\tcode="); + str_append(str, code); +@@ -368,7 +319,6 @@ void auth_request_handler_reply(struct auth_request *request, + { + struct auth_request_handler *handler = request->handler; + +- request->handler_pending_reply = FALSE; + handler->reply_callback(request, result, auth_reply, reply_size); + } + +@@ -442,15 +392,6 @@ auth_request_handler_default_reply_continue(struct auth_request *request, + reply, reply_size); + } + +-void auth_request_handler_abort(struct auth_request *request) +-{ +- i_assert(request->handler_pending_reply); +- +- /* request destroyed while waiting for auth_request_penalty_finish() +- to be called. */ +- auth_request_handler_unref(&request->handler); +-} +- + static void + auth_request_handler_auth_fail_code(struct auth_request_handler *handler, + struct auth_request *request, +@@ -497,29 +438,6 @@ static void auth_request_timeout(struct auth_request *request) + auth_request_handler_remove(request->handler, request); + } + +-static void auth_request_penalty_finish(struct auth_request *request) +-{ +- timeout_remove(&request->to_penalty); +- auth_request_initial(request); +-} +- +-static void +-auth_penalty_callback(unsigned int penalty, struct auth_request *request) +-{ +- unsigned int secs; +- +- request->last_penalty = penalty; +- +- if (penalty == 0) +- auth_request_initial(request); +- else { +- secs = auth_penalty_to_secs(penalty); +- request->to_penalty = timeout_add(secs * 1000, +- auth_request_penalty_finish, +- request); +- } +-} +- + bool auth_request_handler_auth_begin(struct auth_request_handler *handler, + const char *args) + { +@@ -683,10 +601,8 @@ bool auth_request_handler_auth_begin(struct auth_request_handler *handler, + /* handler is referenced until auth_request_handler_reply() + is called. */ + handler->refcount++; +- request->handler_pending_reply = TRUE; + +- /* before we start authenticating, see if we need to wait first */ +- auth_penalty_lookup(auth_penalty, request, auth_penalty_callback); ++ auth_request_initial(request); + return TRUE; + } + +@@ -911,75 +827,3 @@ void auth_request_handler_cancel_request(struct auth_request_handler *handler, + if (request != NULL) + auth_request_handler_remove(handler, request); + } +- +-void auth_request_handler_flush_failures(bool flush_all) +-{ +- struct auth_request **auth_requests, *auth_request; +- unsigned int i, j, count; +- time_t diff; +- +- count = aqueue_count(auth_failures); +- if (count == 0) { +- timeout_remove(&to_auth_failures); +- return; +- } +- +- auth_requests = array_front_modifiable(&auth_failures_arr); +- /* count the number of requests that we need to flush */ +- for (i = 0; i < count; i++) { +- auth_request = auth_requests[aqueue_idx(auth_failures, i)]; +- +- /* FIXME: assumes that failure_delay is always the same. */ +- diff = ioloop_time - auth_request->last_access; +- if (diff < (time_t)auth_request->set->failure_delay && +- !flush_all) +- break; +- } +- +- /* shuffle these requests to try to prevent any kind of timing attacks +- where attacker performs multiple requests in parallel and attempts +- to figure out results based on the order of replies. */ +- count = i; +- for (i = 0; i < count; i++) { +- j = random() % (count - i) + i; +- auth_request = auth_requests[aqueue_idx(auth_failures, i)]; +- +- /* swap i & j */ +- auth_requests[aqueue_idx(auth_failures, i)] = +- auth_requests[aqueue_idx(auth_failures, j)]; +- auth_requests[aqueue_idx(auth_failures, j)] = auth_request; +- } +- +- /* flush the requests */ +- for (i = 0; i < count; i++) { +- auth_request = auth_requests[aqueue_idx(auth_failures, 0)]; +- aqueue_delete_tail(auth_failures); +- +- i_assert(auth_request != NULL); +- i_assert(auth_request->state == AUTH_REQUEST_STATE_FINISHED); +- auth_request_handler_reply(auth_request, +- AUTH_CLIENT_RESULT_FAILURE, +- uchar_empty_ptr, 0); +- auth_request_unref(&auth_request); +- } +-} +- +-static void auth_failure_timeout(void *context ATTR_UNUSED) +-{ +- auth_request_handler_flush_failures(FALSE); +-} +- +-void auth_request_handler_init(void) +-{ +- i_array_init(&auth_failures_arr, 128); +- auth_failures = aqueue_init(&auth_failures_arr.arr); +-} +- +-void auth_request_handler_deinit(void) +-{ +- auth_request_handler_flush_failures(TRUE); +- array_free(&auth_failures_arr); +- aqueue_deinit(&auth_failures); +- +- timeout_remove(&to_auth_failures); +-} +diff --git a/src/auth/auth-request-handler.h b/src/auth/auth-request-handler.h +index ceba9356c5..780e8d236a 100644 +--- a/src/auth/auth-request-handler.h ++++ b/src/auth/auth-request-handler.h +@@ -50,7 +50,6 @@ void auth_request_handler_reply(struct auth_request *request, + const void *reply, size_t reply_size); + void auth_request_handler_reply_continue(struct auth_request *request, + const void *reply, size_t reply_size); +-void auth_request_handler_abort(struct auth_request *request); + + unsigned int + auth_request_handler_get_request_count(struct auth_request_handler *handler); +@@ -61,9 +60,4 @@ bool auth_request_handler_master_request(struct auth_request_handler *handler, + void auth_request_handler_cancel_request(struct auth_request_handler *handler, + unsigned int client_id); + +-void auth_request_handler_flush_failures(bool flush_all); +- +-void auth_request_handler_init(void); +-void auth_request_handler_deinit(void); +- + #endif +diff --git a/src/auth/auth-request.c b/src/auth/auth-request.c +index ee89e75308..7aa5f97022 100644 +--- a/src/auth/auth-request.c ++++ b/src/auth/auth-request.c +@@ -331,9 +331,6 @@ void auth_request_unref(struct auth_request **_request) + + i_assert(array_count(&request->authdb_event) == 0); + +- if (request->handler_pending_reply) +- auth_request_handler_abort(request); +- + event_unref(&request->mech_event); + event_unref(&request->event); + auth_request_stats_send(request); +diff --git a/src/auth/auth-request.h b/src/auth/auth-request.h +index 79cf76b585..9dba941646 100644 +--- a/src/auth/auth-request.h ++++ b/src/auth/auth-request.h +@@ -139,7 +139,6 @@ struct auth_request { + + struct timeout *to_abort, *to_penalty; + unsigned int policy_penalty; +- unsigned int last_penalty; + size_t initial_response_len; + const unsigned char *initial_response; + +@@ -185,10 +184,8 @@ struct auth_request { + bool userdbs_seen_internal_failure:1; + + /* current state: */ +- bool handler_pending_reply:1; + bool accept_cont_input:1; + bool prefer_plain_credentials:1; +- bool in_delayed_failure_queue:1; + bool removed_from_handler:1; + bool snapshot_have_userdb_prefetch_set:1; + /* username was changed by this passdb/userdb lookup. Used by +diff --git a/src/auth/auth.h b/src/auth/auth.h +index 3ca5a9bb12..aab6f07bd2 100644 +--- a/src/auth/auth.h ++++ b/src/auth/auth.h +@@ -76,8 +76,6 @@ struct auth { + struct auth_userdb *userdbs; + }; + +-extern struct auth_penalty *auth_penalty; +- + struct auth *auth_find_service(const char *name); + struct auth *auth_default_service(void); + +diff --git a/src/auth/main.c b/src/auth/main.c +index de4a8263cc..b2ec7f81ea 100644 +--- a/src/auth/main.c ++++ b/src/auth/main.c +@@ -22,7 +22,6 @@ + #include "otp.h" + #include "mech-otp-common.h" + #include "auth.h" +-#include "auth-penalty.h" + #include "auth-token.h" + #include "auth-request-handler.h" + #include "auth-request-stats.h" +@@ -35,8 +34,6 @@ + #include + #include + +-#define AUTH_PENALTY_ANVIL_PATH "anvil-auth-penalty" +- + enum auth_socket_type { + AUTH_SOCKET_UNKNOWN = 0, + AUTH_SOCKET_CLIENT, +@@ -55,7 +52,6 @@ struct auth_socket_listener { + + bool worker = FALSE, worker_restart_request = FALSE; + time_t process_start_time; +-struct auth_penalty *auth_penalty; + + static pool_t auth_set_pool; + static struct module *modules = NULL; +@@ -172,8 +168,6 @@ static void main_preinit(void) + + services = read_global_settings(); + +- if (!worker) +- auth_penalty = auth_penalty_init(AUTH_PENALTY_ANVIL_PATH); + auth_request_stats_init(); + mech_init(global_auth_settings); + mech_reg = mech_register_init(global_auth_settings); +@@ -211,7 +205,6 @@ static void main_init(void) + child_wait_init(); + auth_worker_server_init(); + auths_init(); +- auth_request_handler_init(); + auth_policy_init(); + + if (worker) { +@@ -232,16 +225,10 @@ static void main_deinit(void) + { + struct auth_socket_listener *l; + +- if (auth_penalty != NULL) { +- /* cancel all pending anvil penalty lookups */ +- auth_penalty_deinit(&auth_penalty); +- } + /* deinit auth workers, which aborts pending requests */ + auth_worker_server_deinit(); + /* deinit passdbs and userdbs. it aborts any pending async requests. */ + auths_deinit(); +- /* flush pending requests */ +- auth_request_handler_deinit(); + /* there are no more auth requests */ + auths_free(); + dict_drivers_unregister_builtin(); +diff --git a/src/auth/test-mech.c b/src/auth/test-mech.c +index 265ed37cf3..ad77458e1c 100644 +--- a/src/auth/test-mech.c ++++ b/src/auth/test-mech.c +@@ -145,6 +145,7 @@ static void test_mech_prepare_request(struct auth_request **request_r, + request->userdb = auth->userdbs; + handler->refcount = 1; + ++ /* nodelay is no longer meaningful (we no longer indulge in the rude security theatrics of delayed reporting of login failure), but it might as well stay in the test code since it might be used by existing systems. */ + auth_fields_add(request->fields.extra_fields, "nodelay", "", 0); + auth_request_ref(request); + auth_request_state_count[AUTH_REQUEST_STATE_NEW] = 1; +diff --git a/src/auth/test-mock.c b/src/auth/test-mock.c +index 9584912f35..cdfe91c30c 100644 +--- a/src/auth/test-mock.c ++++ b/src/auth/test-mock.c +@@ -4,7 +4,6 @@ + #include "auth-common.h" + #include "passdb.h" + +-struct auth_penalty *auth_penalty; + time_t process_start_time; + bool worker, worker_restart_request; + static struct passdb_module *mock_passdb_mod = NULL; diff -uNr a/gports/openssh/build.sh b/gports/openssh/build.sh --- a/gports/openssh/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/openssh/build.sh 1970-01-01 00:00:00 +0000 @@ -1,12 +1,13 @@ P=openssh V=7.5p1 MAJOR=0 -MINOR=1 +MINOR=2 -# Build requires: autoconf libressl zlib +# Build requires: autoconf automake libressl zlib S=" $P-$V.tar.gz http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/$P-$V.tar.gz +openssh-7.5p1-sftp-flush-prompt.patch sshd.run sshd_config_gales " @@ -20,13 +21,18 @@ root=$PWD/root tar xf $P-$V.tar.gz cd $P-$V + patch -p1 <../openssh-7.5p1-sftp-flush-prompt.patch rm configure config.h.in - # FIXME: these are copied generic files, but even "autoreconf -fis" fails to detect that they're needed so as to install the standard ones - #rm config.guess install-sh mkinstalldirs + # Use standard/system versions of these generic scripts. (Sometimes `autoreconf -fi` seems able to do this automatically, but not here. `automake --add-missing` also fails because this isn't otherwise an automake project.) + for f in config.guess config.sub install-sh mkinstalldirs ; do + rm $f + cp /gales/pkg/automake/automake-1.15/$f . + # XXX what if /gales/pkg/automake is a different version? Do we scan automake* here looking for the automake-1.15 subdir? Symlink it at a higher level in the automake port so multiple versions can be referenced at fixed paths? Symlink it to an unversioned "automake" subdir in the automake port so "the current active version" can be referenced at a fixed path? I like the last one : if we update automake, it will be for a reason so presumably we'd want everything to use the new version where possible. + done autoconf autoheader # Low optimization as this is security-critical - CFLAGS=-O1 ./configure --prefix=/gales/pkg/$Q --sysconfdir=/etc/ssh \ + CFLAGS="-O1 -g" ./configure --prefix=/gales/pkg/$Q --sysconfdir=/etc/ssh \ --disable-pkcs11 \ --disable-etc-default-login \ --with-pie \ @@ -34,6 +40,7 @@ --with-zlib=/gales/pkg/zlib \ --with-ssl-dir=/gales/pkg/libressl \ --disable-lastlog \ + --disable-strip \ --disable-utmp \ --disable-utmpx \ --disable-wtmp \ diff -uNr a/gports/openssh/openssh-7.5p1-sftp-flush-prompt.patch b/gports/openssh/openssh-7.5p1-sftp-flush-prompt.patch --- a/gports/openssh/openssh-7.5p1-sftp-flush-prompt.patch 1970-01-01 00:00:00 +0000 +++ b/gports/openssh/openssh-7.5p1-sftp-flush-prompt.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,15 @@ +diff -ur a/sftp.c b/sftp.c +--- a/sftp.c 2017-03-20 02:39:27 +0000 ++++ b/sftp.c 2023-09-18 00:37:24 +0000 +@@ -2124,8 +2124,10 @@ + signal(SIGINT, SIG_IGN); + + if (el == NULL) { +- if (interactive) ++ if (interactive) { + printf("sftp> "); ++ fflush(stdout); ++ } + if (fgets(cmd, sizeof(cmd), infile) == NULL) { + if (interactive) + printf("\n"); diff -uNr a/gports/pcre/Makefile b/gports/pcre/Makefile --- a/gports/pcre/Makefile 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/Makefile 1970-01-01 00:00:00 +0000 @@ -0,0 +1,54 @@ +# Constructed following docs in NON-AUTOTOOLS-BUILD. +# Not building: 16- and 32-bit character versions (libpcre16, libpcre32); POSIX wrappers (libpcreposix); C++ wrappers (libpcrecpp); pcregrep. + +# for cross compiling: +BUILD_CC = $(CC) + +CFLAGS = -g -O1 -ansi -Wall -Wextra +CPPFLAGS = -DHAVE_CONFIG_H -I. + +all: libpcre.a pcretest + +dftables: dftables.c + $(BUILD_CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ + +pcre_chartables.c: dftables + ./dftables $@ + +PCRE8_OBJS = \ + pcre_byte_order.o \ + pcre_chartables.o \ + pcre_compile.o \ + pcre_config.o \ + pcre_dfa_exec.o \ + pcre_exec.o \ + pcre_fullinfo.o \ + pcre_get.o \ + pcre_globals.o \ + pcre_jit_compile.o \ + pcre_maketables.o \ + pcre_newline.o \ + pcre_ord2utf8.o \ + pcre_refcount.o \ + pcre_string_utils.o \ + pcre_study.o \ + pcre_tables.o \ + pcre_ucd.o \ + pcre_valid_utf8.o \ + pcre_version.o \ + pcre_xclass.o \ + +libpcre.a: $(PCRE8_OBJS) + $(AR) -rcs $@ $^ + +pcretest.o: pcretest.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DNOPOSIX -c -o $@ $^ + +pcretest: pcretest.o pcre_printint.o libpcre.a + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +check: pcretest + ./RunTest + +clean: + rm -f libpcre.a pcretest dftables pcre_chartables.c $(PCRE8_OBJS) diff -uNr a/gports/pcre/build.sh b/gports/pcre/build.sh --- a/gports/pcre/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/build.sh 1970-01-01 00:00:00 +0000 @@ -0,0 +1,52 @@ +P=pcre +V=8.45 +MAJOR=0 +MINOR=0 + +# So far we try to get away without UTF8 decoding, Unicode character properties, 16- or 32-bit character support, POSIX regex API wrappers, C++ wrappers, or the user programs (pcre-config pcregrep pcretest). + +S=" +$P-$V.tar.bz2 +Makefile +config.h +pcre-drop-slashp-tests.patch +" + +SHA512=" +91bff52eed4a2dfc3f3bfdc9c672b88e7e2ffcf3c4b121540af8a4ae8c1ce05178430aa6b8000658b9bb7b4252239357250890e20ceb84b79cdfcde05154061a pcre-8.45.tar.bz2 +" + +build () { + root=$PWD/root + tar xjf $P-$V.tar.bz2 + cd $P-$V + patch -p1 <../pcre-drop-slashp-tests.patch + cp ../Makefile ../config.h . + mv pcre.h.generic pcre.h + make -j$JOBS +} + +check () { + cd $P-$V + make check +} + +package () { + cd $P-$V + f gales/pkg/$Q/doc/AUTHORS + f gales/pkg/$Q/doc/ChangeLog + f gales/pkg/$Q/doc/LICENCE + f gales/pkg/$Q/doc/NEWS + f gales/pkg/$Q/doc/README + f gales/pkg/$Q/include/pcre.h + F gales/pkg/$Q/lib/libpcre.a + cd doc + for f in *.3 ; do + f gales/pkg/$Q/man/man3/$f + done + # Skipping *.1 as we're not presently installing any user programs. + # There's also doc/*.txt and doc/html but these are generated from the man pages. + l gales/pkg/$P $Q + l gales/doc/$P ../pkg/$P/doc + l gales/man/$P ../pkg/$P/man +} diff -uNr a/gports/pcre/config.h b/gports/pcre/config.h --- a/gports/pcre/config.h 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/config.h 1970-01-01 00:00:00 +0000 @@ -0,0 +1,56 @@ +/* Distilled from config.h.generic and autoconf output */ + +/* #undef BSR_ANYCRLF */ +/* #undef EBCDIC */ +/* #undef EBCDIC_NL25 */ +#define HAVE_BCOPY 1 +#define HAVE_DIRENT_H 1 +/* #undef HAVE_EDITLINE_READLINE_H */ +/* #undef HAVE_EDIT_READLINE_READLINE_H */ +#define HAVE_INTTYPES_H 1 +#define HAVE_LONG_LONG 1 +#define HAVE_MEMMOVE 1 +/* #undef HAVE_READLINE_HISTORY_H */ +/* #undef HAVE_READLINE_READLINE_H */ +#define HAVE_STDINT_H 1 +#define HAVE_STRERROR 1 +/* #undef HAVE_STRTOIMAX */ +#define HAVE_STRTOLL 1 +/* #undef HAVE_STRTOQ */ +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +/* #undef HAVE_TYPE_TRAITS_H */ +#define HAVE_UNISTD_H 1 +#define HAVE_UNSIGNED_LONG_LONG 1 +/* #undef HAVE_WINDOWS_H */ +/* #undef HAVE__STRTOI64 */ +#define LINK_SIZE 2 +#define MATCH_LIMIT 10000000 +#define MATCH_LIMIT_RECURSION MATCH_LIMIT +#define MAX_NAME_COUNT 10000 +#define MAX_NAME_SIZE 32 +#define NEWLINE 10 +/* #undef NO_RECURSE */ +#define PARENS_NEST_LIMIT 250 +#define PCRECPP_EXP_DECL extern __attribute__ ((visibility ("default"))) +#define PCRECPP_EXP_DEFN __attribute__ ((visibility ("default"))) +#define PCREPOSIX_EXP_DECL extern __attribute__ ((visibility ("default"))) +#define PCREPOSIX_EXP_DEFN extern __attribute__ ((visibility ("default"))) +#define PCRE_EXP_DATA_DEFN __attribute__ ((visibility ("default"))) +#define PCRE_EXP_DECL extern __attribute__ ((visibility ("default"))) +#define PCRE_EXP_DEFN __attribute__ ((visibility ("default"))) +#define PCREGREP_BUFSIZE 20480 +#define PCRE_STATIC 1 +#define POSIX_MALLOC_THRESHOLD 10 +/* #undef SUPPORT_JIT */ +/* #undef SUPPORT_LIBBZ2 */ +/* #undef SUPPORT_LIBEDIT */ +/* #undef SUPPORT_LIBREADLINE */ +/* #undef SUPPORT_LIBZ */ +/* #undef SUPPORT_PCRE16 */ +/* #undef SUPPORT_PCRE32 */ +#define SUPPORT_PCRE8 1 +/* #undef SUPPORT_PCREGREP_JIT */ +/* #undef SUPPORT_UCP */ +/* #undef SUPPORT_UTF */ +/* #undef SUPPORT_VALGRIND */ diff -uNr a/gports/pcre/pcre-drop-slashp-tests.patch b/gports/pcre/pcre-drop-slashp-tests.patch --- a/gports/pcre/pcre-drop-slashp-tests.patch 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/pcre-drop-slashp-tests.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,245 @@ +We're not building the POSIX wrapper interfaces library, so /P doesn't work and throws "** Unknown modifier 'P'". + -jfw + +diff -ur a/testdata/testinput14 b/testdata/testinput14 +--- a/testdata/testinput14 2023-08-24 05:04:11 +0000 ++++ b/testdata/testinput14 2023-08-24 05:05:02 +0000 +@@ -1,88 +1,9 @@ + /-- This set of tests is run only with the 8-bit library. They do not require +- UTF-8 or Unicode property support. The file starts with all the tests of +- the POSIX interface, because that is supported only with the 8-bit library. ++ UTF-8 or Unicode property support. + --/ + + < forbid 8W + +-/abc/P +- abc +- *** Failers +- +-/^abc|def/P +- abcdef +- abcdef\B +- +-/.*((abc)$|(def))/P +- defabc +- \Zdefabc +- +-/the quick brown fox/P +- the quick brown fox +- *** Failers +- The Quick Brown Fox +- +-/the quick brown fox/Pi +- the quick brown fox +- The Quick Brown Fox +- +-/abc.def/P +- *** Failers +- abc\ndef +- +-/abc$/P +- abc +- abc\n +- +-/(abc)\2/P +- +-/(abc\1)/P +- abc +- +-/a*(b+)(z)(z)/P +- aaaabbbbzzzz +- aaaabbbbzzzz\O0 +- aaaabbbbzzzz\O1 +- aaaabbbbzzzz\O2 +- aaaabbbbzzzz\O3 +- aaaabbbbzzzz\O4 +- aaaabbbbzzzz\O5 +- +-/ab.cd/P +- ab-cd +- ab=cd +- ** Failers +- ab\ncd +- +-/ab.cd/Ps +- ab-cd +- ab=cd +- ab\ncd +- +-/a(b)c/PN +- abc +- +-/a(?Pb)c/PN +- abc +- +-/a?|b?/P +- abc +- ** Failers +- ddd\N +- +-/\w+A/P +- CDAAAAB +- +-/\w+A/PU +- CDAAAAB +- +-/\Biss\B/I+P +- Mississippi +- +-/abc/\P +- +-/-- End of POSIX tests --/ +- + /a\Cb/ + aXb + a\nb +diff -ur a/testdata/testoutput14 b/testdata/testoutput14 +--- a/testdata/testoutput14 2023-08-24 05:05:18 +0000 ++++ b/testdata/testoutput14 2023-08-24 05:05:36 +0000 +@@ -1,144 +1,9 @@ + /-- This set of tests is run only with the 8-bit library. They do not require +- UTF-8 or Unicode property support. The file starts with all the tests of +- the POSIX interface, because that is supported only with the 8-bit library. ++ UTF-8 or Unicode property support. + --/ + + < forbid 8W + +-/abc/P +- abc +- 0: abc +- *** Failers +-No match: POSIX code 17: match failed +- +-/^abc|def/P +- abcdef +- 0: abc +- abcdef\B +- 0: def +- +-/.*((abc)$|(def))/P +- defabc +- 0: defabc +- 1: abc +- 2: abc +- \Zdefabc +- 0: def +- 1: def +- 3: def +- +-/the quick brown fox/P +- the quick brown fox +- 0: the quick brown fox +- *** Failers +-No match: POSIX code 17: match failed +- The Quick Brown Fox +-No match: POSIX code 17: match failed +- +-/the quick brown fox/Pi +- the quick brown fox +- 0: the quick brown fox +- The Quick Brown Fox +- 0: The Quick Brown Fox +- +-/abc.def/P +- *** Failers +-No match: POSIX code 17: match failed +- abc\ndef +-No match: POSIX code 17: match failed +- +-/abc$/P +- abc +- 0: abc +- abc\n +- 0: abc +- +-/(abc)\2/P +-Failed: POSIX code 15: bad back reference at offset 7 +- +-/(abc\1)/P +- abc +-No match: POSIX code 17: match failed +- +-/a*(b+)(z)(z)/P +- aaaabbbbzzzz +- 0: aaaabbbbzz +- 1: bbbb +- 2: z +- 3: z +- aaaabbbbzzzz\O0 +- aaaabbbbzzzz\O1 +- 0: aaaabbbbzz +- aaaabbbbzzzz\O2 +- 0: aaaabbbbzz +- 1: bbbb +- aaaabbbbzzzz\O3 +- 0: aaaabbbbzz +- 1: bbbb +- 2: z +- aaaabbbbzzzz\O4 +- 0: aaaabbbbzz +- 1: bbbb +- 2: z +- 3: z +- aaaabbbbzzzz\O5 +- 0: aaaabbbbzz +- 1: bbbb +- 2: z +- 3: z +- +-/ab.cd/P +- ab-cd +- 0: ab-cd +- ab=cd +- 0: ab=cd +- ** Failers +-No match: POSIX code 17: match failed +- ab\ncd +-No match: POSIX code 17: match failed +- +-/ab.cd/Ps +- ab-cd +- 0: ab-cd +- ab=cd +- 0: ab=cd +- ab\ncd +- 0: ab\x0acd +- +-/a(b)c/PN +- abc +-Matched with REG_NOSUB +- +-/a(?Pb)c/PN +- abc +-Matched with REG_NOSUB +- +-/a?|b?/P +- abc +- 0: a +- ** Failers +- 0: +- ddd\N +-No match: POSIX code 17: match failed +- +-/\w+A/P +- CDAAAAB +- 0: CDAAAA +- +-/\w+A/PU +- CDAAAAB +- 0: CDA +- +-/\Biss\B/I+P +- Mississippi +- 0: iss +- 0+ issippi +- +-/abc/\P +-Failed: POSIX code 9: bad escape sequence at offset 4 +- +-/-- End of POSIX tests --/ +- + /a\Cb/ + aXb + 0: aXb diff -uNr a/gports/qmail/build.sh b/gports/qmail/build.sh --- a/gports/qmail/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/build.sh 1970-01-01 00:00:00 +0000 @@ -1,9 +1,9 @@ P=qmail V=1.03 MAJOR=0 -MINOR=0 +MINOR=1 -# Recommended: ucspi-tcp [for smtp] +# TODO refresh & document what & why of no-cname patch S=" $P-$V.tar.gz http://cr.yp.to/software/$P-$V.tar.gz @@ -13,6 +13,14 @@ qmail-1.03.smtpd-blast.patch qmail-1.03.zero-localhost.patch qmail-1.03.alloc-prototype.patch +qmail-1.03.qmtpd-netstring.patch +qmail-1.03.build-flags-warnings.patch +qmail-1.03.syncdir.patch +syncdir.c +qmail.run +smtp.run +submission.run +wrap-qmail-remote.sh " SHA512=" @@ -28,13 +36,28 @@ patch -p1 <../qmail-1.03.smtpd-blast.patch patch -p1 <../qmail-1.03.zero-localhost.patch patch -p1 <../qmail-1.03.alloc-prototype.patch - make - make dot-qmail.5 qmail-control.5 qmail-getpw.8 qmail-limits.7 qmail-newmrh.8 qmail-newu.8 qmail-pw2u.8 qmail-send.8 qmail-start.8 qmail-users.5 + patch -p1 <../qmail-1.03.qmtpd-netstring.patch + patch -p1 <../qmail-1.03.build-flags-warnings.patch + patch -p1 <../qmail-1.03.syncdir.patch + cp ../syncdir.c . + make -j$JOBS + make -j$JOBS dot-qmail.5 qmail-control.5 qmail-getpw.8 qmail-limits.7 qmail-newmrh.8 qmail-newu.8 qmail-pw2u.8 qmail-send.8 qmail-start.8 qmail-users.5 dd if=/dev/zero of=tcpto bs=1 count=1024 true >sendmutex } package () { + x etc/examples/svc/qmail/run qmail.run + l etc/examples/svc/qmail/log/run /etc/svc.defs/multilog + + x etc/examples/svc/qmail-smtp/run smtp.run + l etc/examples/svc/qmail-smtp/log/run /etc/svc.defs/multilog + + x etc/examples/svc/qmail-submission/run submission.run + l etc/examples/svc/qmail-submission/log/run /etc/svc.defs/multilog + + x var/qmail/wrap/qmail-remote wrap-qmail-remote.sh + cd $P-$V # per hier.c d var/qmail 755 root:qmail @@ -94,8 +117,14 @@ f var/qmail/doc/$f done - l gales/doc/qmail /var/qmail/doc - l gales/man/qmail /var/qmail/man + l gales/doc/qmail ../../var/qmail/doc + l gales/man/qmail ../../var/qmail/man + l bin/sendmail ../var/qmail/bin/sendmail + + i 'Binaries are in /var/qmail/bin including the setuid qmail-queue.' + i '/var/qmail/queue has been initialized.' + # TODO test + i '/var/qmail/bin/config or config-fast may be used to set up control files.' } dsplit () { diff -uNr a/gports/qmail/qmail-1.03.alloc-prototype.patch b/gports/qmail/qmail-1.03.alloc-prototype.patch --- a/gports/qmail/qmail-1.03.alloc-prototype.patch 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/qmail-1.03.alloc-prototype.patch 1970-01-01 00:00:00 +0000 @@ -1,6 +1,9 @@ -qmail-rspawn can segfault at startup (spawn.c line 194) due to a 64-bit pointer -not fitting in the implicit "int" return type without the "alloc" prototype. -(To my knowledge, first reported by "Jan" on the qmail list in 2007.) +qmail-rspawn and possibly qmail-lspawn can segfault at startup (spawn.c line 194) due to a 64-bit pointer not fitting in the implicit "int" return type without the "alloc" prototype. + +To my knowledge, this was first noted and fixed in the "isoc" patch from James Craig Burley in 2004; it was also reported by "Jan" on the qmail list in 2007. + +I have reviewed a copy of the full "isoc" patch, finding nothing else of interest besides this and the "Guninski bug" fix captured in this collection as qmail-1.03.smtpd-blast.patch. + -jfw diff -ur a/spawn.c b/spawn.c diff -uNr a/gports/qmail/qmail-1.03.build-flags-warnings.patch b/gports/qmail/qmail-1.03.build-flags-warnings.patch --- a/gports/qmail/qmail-1.03.build-flags-warnings.patch 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/qmail-1.03.build-flags-warnings.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,105 @@ +This gets me a warning-free build, even with non-default warnings enabled except for the explicit list. + +The possibly significant change is the addition of -fno-builtin-* switches, which prevent gcc from possibly inlining code for its builtin puts and log2 implementations, because the code defines its own functions with those names. + +Optimization level is reduced to 1 for compiler security conservatism. + + -jfw + +diff -ur a/alloc.c b/alloc.c +--- a/alloc.c 1998-06-15 10:53:16 +0000 ++++ b/alloc.c 2023-09-20 01:59:45 +0000 +@@ -1,6 +1,6 @@ + #include "alloc.h" + #include "error.h" +-extern char *malloc(); ++extern void *malloc(); + extern void free(); + + #define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +diff -ur a/conf-cc b/conf-cc +--- a/conf-cc 1998-06-15 10:53:16 +0000 ++++ b/conf-cc 2023-09-20 01:59:45 +0000 +@@ -1,3 +1,3 @@ +-cc -O2 ++cc -O1 -std=gnu89 -fno-builtin-puts -fno-builtin-log2 -Wall -Wextra -Wno-main -Wno-implicit-function-declaration -Wno-parentheses -Wno-pointer-sign -Wno-sign-compare -Wno-empty-body -Wno-unused-parameter -Wno-missing-field-initializers + + This will be used to compile .c files. +diff -ur a/maildir.c b/maildir.c +--- a/maildir.c 1998-06-15 10:53:16 +0000 ++++ b/maildir.c 2023-09-20 01:59:45 +0000 +@@ -95,7 +95,6 @@ + { + struct prioq_elt pe; + datetime_sec time; +- int r; + + if (!stralloc_copys(filenames,"")) return 0; + while (prioq_min(pq,&pe)) prioq_delmin(pq); +diff -ur a/qmail-pw2u.c b/qmail-pw2u.c +--- a/qmail-pw2u.c 1998-06-15 10:53:16 +0000 ++++ b/qmail-pw2u.c 2023-09-20 01:59:45 +0000 +@@ -16,6 +16,7 @@ + #include "auto_break.h" + #include "auto_qmail.h" + #include "auto_usera.h" ++#include "exit.h" + + void die_chdir() + { +diff -ur a/qmail-qmqpc.c b/qmail-qmqpc.c +--- a/qmail-qmqpc.c 1998-06-15 10:53:16 +0000 ++++ b/qmail-qmqpc.c 2023-09-20 01:59:45 +0000 +@@ -135,7 +135,7 @@ + + stralloc servers = {0}; + +-main() ++int main() + { + int i; + int j; +diff -ur a/qmail-qmqpd.c b/qmail-qmqpd.c +--- a/qmail-qmqpd.c 1998-06-15 10:53:16 +0000 ++++ b/qmail-qmqpd.c 2023-09-20 01:59:45 +0000 +@@ -105,7 +105,7 @@ + + int flagok = 1; + +-main() ++int main() + { + char *result; + unsigned long qp; +diff -ur a/qmail-qmtpd.c b/qmail-qmtpd.c +--- a/qmail-qmtpd.c 2023-09-20 01:59:32 +0000 ++++ b/qmail-qmtpd.c 2023-09-20 01:59:45 +0000 +@@ -11,6 +11,7 @@ + #include "readwrite.h" + #include "control.h" + #include "received.h" ++#include "exit.h" + + void badproto() { _exit(100); } + void resources() { _exit(111); } +@@ -76,7 +77,7 @@ + char *relayclient; + int relayclientlen; + +-main() ++int main() + { + char ch; + int i; +diff -ur a/tcpto.c b/tcpto.c +--- a/tcpto.c 1998-06-15 10:53:16 +0000 ++++ b/tcpto.c 2023-09-20 01:59:45 +0000 +@@ -73,7 +73,7 @@ + int i; + char *record; + datetime_sec when; +- datetime_sec firstwhen; ++ datetime_sec firstwhen = 0; /* initialization not strictly required, but satisfies "may be used uninitialized" warning */ + int firstpos; + datetime_sec lastwhen; + diff -uNr a/gports/qmail/qmail-1.03.qmtpd-netstring.patch b/gports/qmail/qmail-1.03.qmtpd-netstring.patch --- a/gports/qmail/qmail-1.03.qmtpd-netstring.patch 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/qmail-1.03.qmtpd-netstring.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,51 @@ +# qmail-1.03.qmtpd-netstring.patch +# +# This patch corrects a programming error in +# the getlen() and main() routines of qmail-qmtpd.c. +# +# These routines read input length in netstring format. +# But the original code does not test for numeric validity +# in the length field of the netstring. +# +# As a consquence, it is possible for an attacker to design +# input to create a buffer overflow. +# +# This patch modifies the original to perform validity +# checking when reading the length field of the netstring. +# +# George Guninski documents this bug at: +# +# http://www.guninski.com/qmail-qmtpd.html +# +# For additional information about qmail and patches, +# see: +# +# http://www.thedjbway.org/qmail/patches.html +# +# PUBLIC DOMAIN. +# NO WARRANTY. +# USE AT YOUR OWN RISK. Etc, etc., etc. +# +# wcm, 2004.10.04 - 2004.10.04 +# === +diff -u qmail-1.03.orig/qmail-qmtpd.c qmail-1.03/qmail-qmtpd.c +--- qmail-1.03.orig/qmail-qmtpd.c Mon Jun 15 03:52:55 1998 ++++ qmail-1.03/qmail-qmtpd.c Mon Oct 4 11:46:03 2004 +@@ -45,6 +45,8 @@ + for (;;) { + substdio_get(&ssin,&ch,1); + if (ch == ':') return len; ++ /* trap non-numeric input in netstring: */ ++ if ((ch < '0') || (ch > '9')) badproto(); + if (len > 200000000) resources(); + len = 10 * len + (ch - '0'); + } +@@ -193,6 +195,8 @@ + substdio_get(&ssin,&ch,1); + --biglen; + if (ch == ':') break; ++ /* trap non-numeric input in netstring: */ ++ if ((ch < '0') || (ch > '9')) badproto(); + if (len > 200000000) resources(); + len = 10 * len + (ch - '0'); + } diff -uNr a/gports/qmail/qmail-1.03.syncdir.patch b/gports/qmail/qmail-1.03.syncdir.patch --- a/gports/qmail/qmail-1.03.syncdir.patch 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/qmail-1.03.syncdir.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,35 @@ +diff -ur a/Makefile b/Makefile +--- a/Makefile 2023-09-26 21:48:45 +0000 ++++ b/Makefile 2023-09-26 21:50:55 +0000 +@@ -798,8 +798,12 @@ + instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ + binm3 binm3+df + ++libsyncdir.a: \ ++makelib syncdir.o ++ ./makelib libsyncdir.a syncdir.o ++ + load: \ +-make-load warn-auto.sh systype ++make-load warn-auto.sh systype libsyncdir.a + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +@@ -2041,6 +2045,10 @@ + compile substdo.c substdio.h str.h byte.h error.h + ./compile substdo.c + ++syncdir.o: \ ++compile syncdir.c ++ ./compile syncdir.c ++ + syslog.lib: \ + trysyslog.c compile load + ( ( ./compile trysyslog.c && \ +diff -ur a/make-load.sh b/make-load.sh +--- a/make-load.sh 1998-06-15 10:53:16 +0000 ++++ b/make-load.sh 2023-09-26 21:51:05 +0000 +@@ -1,2 +1,2 @@ + echo 'main="$1"; shift' +-echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}' ++echo exec "$LD" '-o "$main" "$main".o ${1+"$@"} -L. -lsyncdir' diff -uNr a/gports/qmail/qmail.run b/gports/qmail/qmail.run --- a/gports/qmail/qmail.run 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/qmail.run 1970-01-01 00:00:00 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +PATH=/var/qmail/wrap:/var/qmail/bin:$PATH exec qmail-start ./Maildir/ 2>&1 diff -uNr a/gports/qmail/smtp.run b/gports/qmail/smtp.run --- a/gports/qmail/smtp.run 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/smtp.run 1970-01-01 00:00:00 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec tcpsvd -l 0 -u qmaild -v 0 smtp /var/qmail/bin/qmail-smtpd 2>&1 diff -uNr a/gports/qmail/submission.run b/gports/qmail/submission.run --- a/gports/qmail/submission.run 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/submission.run 1970-01-01 00:00:00 +0000 @@ -0,0 +1,4 @@ +#!/bin/sh +RELAYCLIENT= exec tcpsvd -l 0 -u qmaild -v 0 submission /var/qmail/bin/qmail-smtpd 2>&1 +# !! IMPORTANT !! +# Restrict 'submission' port to trusted networks to prevent open relay. diff -uNr a/gports/qmail/syncdir.c b/gports/qmail/syncdir.c --- a/gports/qmail/syncdir.c 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/syncdir.c 1970-01-01 00:00:00 +0000 @@ -0,0 +1,95 @@ +/* syncdir -- emulate synchronous directories + This is free and unencumbered software released into the public domain. + [ from Bruce Guenter, http://untroubled.org/syncdir/ ] +*/ + +#include +#include +#define open XXX_open +#include +#undef open +#include +#include +#include +#include +#include + +#define SYS_OPEN(FILE,FLAG,MODE) syscall(SYS_open, FILE, FLAG, MODE) +#define SYS_CLOSE(FD) syscall(SYS_close, FD) +#define SYS_LINK(OLD,NEW) syscall(SYS_link, OLD, NEW) +#define SYS_UNLINK(PATH) syscall(SYS_unlink, PATH) +#define SYS_RENAME(OLD,NEW) syscall(SYS_rename, OLD, NEW) +#define SYS_FSYNC(FD) syscall(SYS_fsync, FD) + +static int fdirsync(const char* filename, unsigned length) +{ + char dirname[length+1]; + /* This could also be: + * char* dirname = alloca(length+1); */ + int dirfd; + int retval; + memcpy(dirname, filename, length); + dirname[length] = 0; + if((dirfd = SYS_OPEN(dirname,O_RDONLY,0)) == -1) + return -1; + retval = (SYS_FSYNC(dirfd) == -1 && errno == EIO) ? -1 : 0; + SYS_CLOSE(dirfd); + return retval; +} + +static int fdirsyncfn(const char *filename) +{ + const char *slash = filename+strlen(filename)-1; + + /* Skip over trailing slashes, which would be ignored by some + * operations */ + while(slash > filename && *slash == '/') + --slash; + + /* Skip back to the next slash */ + while(slash > filename && *slash != '/') + --slash; + + /* slash now either points to a '/' character, or no slash was found */ + if(*slash == '/') + return fdirsync(filename, + (slash == filename) ? 1 : slash-filename); + else + return fdirsync(".", 1); +} + +int open(const char *file,int oflag,mode_t mode) +{ + int fd = SYS_OPEN(file, oflag, mode); + if(fd == -1) + return fd; + if(oflag & O_CREAT) + if(fdirsyncfn(file) == -1) { + SYS_CLOSE(fd); + return -1; + } + return fd; +} + +int link(const char *oldpath,const char *newpath) +{ + if(SYS_LINK(oldpath,newpath) == -1) + return -1; + return fdirsyncfn(newpath); +} + +int unlink(const char *path) +{ + if(SYS_UNLINK(path) == -1) + return -1; + return fdirsyncfn(path); +} + +int rename(const char *oldpath,const char *newpath) +{ + if(SYS_RENAME(oldpath,newpath) == -1) + return -1; + if(fdirsyncfn(newpath) == -1) + return -1; + return fdirsyncfn(oldpath); +} diff -uNr a/gports/qmail/wrap-qmail-remote.sh b/gports/qmail/wrap-qmail-remote.sh --- a/gports/qmail/wrap-qmail-remote.sh 1970-01-01 00:00:00 +0000 +++ b/gports/qmail/wrap-qmail-remote.sh 1970-01-01 00:00:00 +0000 @@ -0,0 +1,13 @@ +#!/bin/sh + +# Install as /var/qmail/wrap/qmail-remote, with /var/qmail/wrap in qmail-send's $PATH before /var/qmail/bin. + +# This drops bounce messages (empty envelope sender) destined for "external" domains as delineated by rcpthosts (messages to locals are passed to qmail-local, not qmail-remote, so they don't enter here at all). It's a crude measure against backscatter spam, preventing us from being usable as an open relay/traffic reflector by way of forged SMTP return paths. A smarter solution would be to implement SPF or similar sender IP checking on the SMTP intake side, to address the root problem of easy sender forgery. + +host=$1 +sender=$2 +if [ -z "$sender" ] && ! grep -Fixq "$host" /var/qmail/control/rcpthosts; then + printf 'Kdropped external bounce\0' + exit 0 +fi +exec /var/qmail/bin/qmail-remote "$@" diff -uNr a/gports/strace/build.sh b/gports/strace/build.sh --- a/gports/strace/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/strace/build.sh 1970-01-01 00:00:00 +0000 @@ -11,6 +11,7 @@ generate_mpers_am.sh strace-4.16-futex-test-einval.patch strace-4.16-xlat-gen-ksh.patch +strace-4.16-sendfile-test-socket-blocked.patch " SHA512=" @@ -23,6 +24,7 @@ cd $P-$V patch -p1 <../strace-4.16-futex-test-einval.patch patch -p1 <../strace-4.16-xlat-gen-ksh.patch + patch -p1 <../strace-4.16-sendfile-test-socket-blocked.patch # broken-by-design test that fails after the release year rm tests/strace-V.test sed -i '/strace-V.test/d' tests/Makefile.am @@ -39,7 +41,7 @@ check () { cd $P-$V - make check + make check -j$JOBS } package () { diff -uNr a/gports/strace/strace-4.16-sendfile-test-socket-blocked.patch b/gports/strace/strace-4.16-sendfile-test-socket-blocked.patch --- a/gports/strace/strace-4.16-sendfile-test-socket-blocked.patch 1970-01-01 00:00:00 +0000 +++ b/gports/strace/strace-4.16-sendfile-test-socket-blocked.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,241 @@ +commit 0af432af9b4496a8648bfe69a5b38c961ace1b4e +Author: Dmitry V. Levin +AuthorDate: Sun Jun 4 21:17:15 2017 +0000 +Commit: Jacob Welsh +CommitDate: Tue Sep 12 00:36:28 2023 +0000 + + tests: avoid hitting SO_SNDBUF limit in sendfile/sendfile64 tests + + Do not assume that an executable is small enough and SO_SNDBUF is large + enough so that the executable could be sendfile'ed into a socket pair. + + * tests/sendfile.c (main): Create a regular file of the right size + to avoid hitting SO_SNDBUF limit. + * tests/sendfile64.c: Likewise. + + Reported-by: Andreas Schwab + +diff --git a/tests/sendfile.c b/tests/sendfile.c +index 23f096b62..b6ac31f35 100644 +--- a/tests/sendfile.c ++++ b/tests/sendfile.c +@@ -35,15 +35,13 @@ + # include + # include + # include ++# include + # include + # include +-# include + + int +-main(int ac, const char **av) ++main(void) + { +- assert(ac == 1); +- + (void) close(0); + if (open("/dev/zero", O_RDONLY) != 0) + perror_msg_and_skip("open: %s", "/dev/zero"); +@@ -52,58 +50,62 @@ main(int ac, const char **av) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) + perror_msg_and_skip("socketpair"); + +- int reg_in = open(av[0], O_RDONLY); +- if (reg_in < 0) +- perror_msg_and_fail("open: %s", av[0]); +- +- struct stat stb; +- assert(fstat(reg_in, &stb) == 0); +- const size_t blen = stb.st_size / 3; +- const size_t alen = stb.st_size - blen; +- assert(S_ISREG(stb.st_mode) && blen > 0); +- +- const size_t page_len = get_page_size(); +- assert(syscall(__NR_sendfile, 0, 1, NULL, page_len) == -1); ++ const unsigned int page_size = get_page_size(); ++ assert(syscall(__NR_sendfile, 0, 1, NULL, page_size) == -1); + if (EBADF != errno) + perror_msg_and_skip("sendfile"); +- printf("sendfile(0, 1, NULL, %lu) = -1 EBADF (%m)\n", +- (unsigned long) page_len); ++ printf("sendfile(0, 1, NULL, %u) = -1 EBADF (%m)\n", page_size); ++ ++ unsigned int file_size = 0; ++ socklen_t optlen = sizeof(file_size); ++ if (getsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &file_size, &optlen)) ++ perror_msg_and_fail("getsockopt"); ++ if (file_size < 1024) ++ error_msg_and_skip("SO_SNDBUF too small: %u", file_size); ++ ++ file_size /= 4; ++ if (file_size / 16 > page_size) ++ file_size = page_size * 16; ++ const unsigned int blen = file_size / 3; ++ const unsigned int alen = file_size - blen; ++ ++ static const char fname[] = "sendfile-tmpfile"; ++ int reg_in = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600); ++ if (reg_in < 0) ++ perror_msg_and_fail("open: %s", fname); ++ if (unlink(fname)) ++ perror_msg_and_fail("unlink: %s", fname); ++ if (ftruncate(reg_in, file_size)) ++ perror_msg_and_fail("ftruncate: %s", fname); + + uint32_t *p_off = tail_alloc(sizeof(uint32_t)); + void *p = p_off + 1; + *p_off = 0; + +- assert(syscall(__NR_sendfile, 0, 1, p, page_len) == -1); +- printf("sendfile(0, 1, %#lx, %lu) = -1 EFAULT (%m)\n", +- (unsigned long) p, (unsigned long) page_len); ++ assert(syscall(__NR_sendfile, 0, 1, p, page_size) == -1); ++ printf("sendfile(0, 1, %p, %u) = -1 EFAULT (%m)\n", p, page_size); + + assert(syscall(__NR_sendfile, sv[1], reg_in, NULL, alen) + == (long) alen); +- printf("sendfile(%d, %d, NULL, %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) alen); ++ printf("sendfile(%d, %d, NULL, %u) = %u\n", ++ sv[1], reg_in, alen, alen); + + p = p_off; + if (syscall(__NR_sendfile, sv[1], reg_in, p_off, alen) != (long) alen) { +- printf("sendfile(%d, %d, %#lx, %lu) = -1 EFAULT (%m)\n", +- sv[1], reg_in, (unsigned long) p_off, +- (unsigned long) alen); ++ printf("sendfile(%d, %d, %#lx, %u) = -1 EFAULT (%m)\n", ++ sv[1], reg_in, (unsigned long) p_off, alen); + --p_off; + *p_off = 0; + assert(syscall(__NR_sendfile, sv[1], reg_in, p_off, alen) + == (long) alen); + } +- printf("sendfile(%d, %d, [0] => [%lu], %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) alen, (unsigned long) alen); ++ printf("sendfile(%d, %d, [0] => [%u], %u) = %u\n", ++ sv[1], reg_in, alen, alen, alen); + +- assert(syscall(__NR_sendfile, sv[1], reg_in, p_off, stb.st_size + 1) ++ assert(syscall(__NR_sendfile, sv[1], reg_in, p_off, file_size + 1) + == (long) blen); +- printf("sendfile(%d, %d, [%lu] => [%lu], %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) stb.st_size, +- (unsigned long) stb.st_size + 1, +- (unsigned long) blen); ++ printf("sendfile(%d, %d, [%u] => [%u], %u) = %u\n", ++ sv[1], reg_in, alen, file_size, file_size + 1, blen); + + if (p_off != p) { + uint64_t *p_off64 = (uint64_t *) p_off; +diff --git a/tests/sendfile64.c b/tests/sendfile64.c +index 7208c3006..37b842b9a 100644 +--- a/tests/sendfile64.c ++++ b/tests/sendfile64.c +@@ -35,15 +35,13 @@ + # include + # include + # include ++# include + # include + # include +-# include + + int +-main(int ac, const char **av) ++main(void) + { +- assert(ac == 1); +- + (void) close(0); + if (open("/dev/zero", O_RDONLY) != 0) + perror_msg_and_skip("open: %s", "/dev/zero"); +@@ -52,50 +50,55 @@ main(int ac, const char **av) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) + perror_msg_and_skip("socketpair"); + +- int reg_in = open(av[0], O_RDONLY); +- if (reg_in < 0) +- perror_msg_and_fail("open: %s", av[0]); +- +- struct stat stb; +- assert(fstat(reg_in, &stb) == 0); +- const size_t blen = stb.st_size / 3; +- const size_t alen = stb.st_size - blen; +- assert(S_ISREG(stb.st_mode) && blen > 0); +- +- const size_t page_len = get_page_size(); +- assert(syscall(__NR_sendfile64, 0, 1, NULL, page_len) == -1); ++ const unsigned int page_size = get_page_size(); ++ assert(syscall(__NR_sendfile64, 0, 1, NULL, page_size) == -1); + if (EBADF != errno) + perror_msg_and_skip("sendfile64"); +- printf("sendfile64(0, 1, NULL, %lu) = -1 EBADF (%m)\n", +- (unsigned long) page_len); ++ printf("sendfile64(0, 1, NULL, %u) = -1 EBADF (%m)\n", page_size); ++ ++ unsigned int file_size = 0; ++ socklen_t optlen = sizeof(file_size); ++ if (getsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &file_size, &optlen)) ++ perror_msg_and_fail("getsockopt"); ++ if (file_size < 1024) ++ error_msg_and_skip("SO_SNDBUF too small: %u", file_size); ++ ++ file_size /= 4; ++ if (file_size / 16 > page_size) ++ file_size = page_size * 16; ++ const unsigned int blen = file_size / 3; ++ const unsigned int alen = file_size - blen; ++ ++ static const char fname[] = "sendfile64-tmpfile"; ++ int reg_in = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600); ++ if (reg_in < 0) ++ perror_msg_and_fail("open: %s", fname); ++ if (unlink(fname)) ++ perror_msg_and_fail("unlink: %s", fname); ++ if (ftruncate(reg_in, file_size)) ++ perror_msg_and_fail("ftruncate: %s", fname); + + uint64_t *p_off = tail_alloc(sizeof(uint64_t)); + void *p = p_off + 1; + *p_off = 0; + +- assert(syscall(__NR_sendfile64, 0, 1, p, page_len) == -1); +- printf("sendfile64(0, 1, %#lx, %lu) = -1 EFAULT (%m)\n", +- (unsigned long) p, (unsigned long) page_len); ++ assert(syscall(__NR_sendfile64, 0, 1, p, page_size) == -1); ++ printf("sendfile64(0, 1, %p, %u) = -1 EFAULT (%m)\n", p, page_size); + + assert(syscall(__NR_sendfile64, sv[1], reg_in, NULL, alen) + == (long) alen); +- printf("sendfile64(%d, %d, NULL, %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) alen); ++ printf("sendfile64(%d, %d, NULL, %u) = %u\n", ++ sv[1], reg_in, alen, alen); + + assert(syscall(__NR_sendfile64, sv[1], reg_in, p_off, alen) + == (long) alen); +- printf("sendfile64(%d, %d, [0] => [%lu], %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) alen, (unsigned long) alen); ++ printf("sendfile64(%d, %d, [0] => [%u], %u) = %u\n", ++ sv[1], reg_in, alen, alen, alen); + +- assert(syscall(__NR_sendfile64, sv[1], reg_in, p_off, stb.st_size + 1) ++ assert(syscall(__NR_sendfile64, sv[1], reg_in, p_off, file_size + 1) + == (long) blen); +- printf("sendfile64(%d, %d, [%lu] => [%lu], %lu) = %lu\n", +- sv[1], reg_in, (unsigned long) alen, +- (unsigned long) stb.st_size, +- (unsigned long) stb.st_size + 1, +- (unsigned long) blen); ++ printf("sendfile64(%d, %d, [%u] => [%u], %u) = %u\n", ++ sv[1], reg_in, alen, file_size, file_size + 1, blen); + + *p_off = 0xcafef00dfacefeedULL; + assert(syscall(__NR_sendfile64, sv[1], reg_in, p_off, 1) == -1); diff -uNr a/kconfig/linux-4.9-x86_64-amd-server.config b/kconfig/linux-4.9-x86_64-amd-server.config --- a/kconfig/linux-4.9-x86_64-amd-server.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-amd-server.config 1970-01-01 00:00:00 +0000 @@ -383,7 +383,7 @@ CONFIG_IOMMU_HELPER=y # CONFIG_MAXSMP is not set CONFIG_NR_CPUS=64 -# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set diff -uNr a/kconfig/seabios-1.9.3-qemu.config b/kconfig/seabios-1.9.3-qemu.config --- a/kconfig/seabios-1.9.3-qemu.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/seabios-1.9.3-qemu.config 1970-01-01 00:00:00 +0000 @@ -0,0 +1,109 @@ +# +# Automatically generated file; DO NOT EDIT. +# SeaBIOS Configuration +# + +# +# General Features +# +# CONFIG_COREBOOT is not set +CONFIG_QEMU=y +# CONFIG_CSM is not set +CONFIG_QEMU_HARDWARE=y +CONFIG_XEN=y +# CONFIG_THREADS is not set +CONFIG_RELOCATE_INIT=y +CONFIG_BOOTMENU=y +# CONFIG_BOOTSPLASH is not set +# CONFIG_BOOTORDER is not set +# CONFIG_ENTRY_EXTRASTACK is not set +CONFIG_MALLOC_UPPERMEMORY=y +CONFIG_ROM_SIZE=0 + +# +# Hardware support +# +CONFIG_ATA=y +# CONFIG_ATA_DMA is not set +# CONFIG_ATA_PIO32 is not set +CONFIG_AHCI=y +CONFIG_SDCARD=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_SCSI=y +CONFIG_PVSCSI=y +CONFIG_ESP_SCSI=y +CONFIG_LSI_SCSI=y +# CONFIG_MEGASAS is not set +# CONFIG_FLOPPY is not set +# CONFIG_FLASH_FLOPPY is not set +CONFIG_PS2PORT=y +CONFIG_USB=y +CONFIG_USB_UHCI=y +CONFIG_USB_OHCI=y +CONFIG_USB_EHCI=y +# CONFIG_USB_XHCI is not set +CONFIG_USB_MSC=y +CONFIG_USB_UAS=y +CONFIG_USB_HUB=y +CONFIG_USB_KEYBOARD=y +CONFIG_SERIAL=y +# CONFIG_LPT is not set +CONFIG_RTC_TIMER=y +CONFIG_HARDWARE_IRQ=y +CONFIG_USE_SMM=y +CONFIG_CALL32_SMM=y +CONFIG_MTRR_INIT=y +# CONFIG_PMTIMER is not set +CONFIG_TSC_TIMER=y + +# +# BIOS interfaces +# +CONFIG_DRIVES=y +CONFIG_CDROM_BOOT=y +CONFIG_CDROM_EMU=y +CONFIG_PCIBIOS=y +CONFIG_APMBIOS=y +CONFIG_PNPBIOS=y +CONFIG_OPTIONROMS=y +# CONFIG_OPTIONROMS_DEPLOYED is not set +CONFIG_PMM=y +CONFIG_BOOT=y +CONFIG_KEYBOARD=y +CONFIG_KBD_CALL_INT15_4F=y +# CONFIG_MOUSE is not set +CONFIG_S3_RESUME=y +CONFIG_VGAHOOKS=y +# CONFIG_DISABLE_A20 is not set +# CONFIG_WRITABLE_UPPERMEMORY is not set +# CONFIG_TCGBIOS is not set + +# +# BIOS Tables +# +CONFIG_PIRTABLE=y +CONFIG_MPTABLE=y +CONFIG_SMBIOS=y +CONFIG_ACPI=y +CONFIG_ACPI_DSDT=y +CONFIG_FW_ROMFILE_LOAD=y + +# +# VGA ROM +# +CONFIG_NO_VGABIOS=y +# CONFIG_VGA_STANDARD_VGA is not set +# CONFIG_VGA_CIRRUS is not set +# CONFIG_VGA_BOCHS is not set +# CONFIG_VGA_GEODEGX2 is not set +# CONFIG_VGA_GEODELX is not set +# CONFIG_BUILD_VGABIOS is not set +CONFIG_VGA_EXTRA_STACK_SIZE=512 + +# +# Debugging +# +CONFIG_DEBUG_LEVEL=1 +CONFIG_DEBUG_SERIAL=y +CONFIG_DEBUG_SERIAL_PORT=0x3f8 +CONFIG_DEBUG_IO=y