]> git.ipfire.org Git - thirdparty/dovecot/core.git/log
thirdparty/dovecot/core.git
2 days agolib-dict-backend: cdb - Fix use-after-realloc of returned key pointer main
rootvector2 [Thu, 21 May 2026 12:56:17 +0000 (18:26 +0530)] 
lib-dict-backend: cdb - Fix use-after-realloc of returned key pointer

cdb_dict_next() reuses ctx->buffer for both the key and the value:
the key is placed at offset 0 of the buffer, and a pointer to it is
returned via *key_r. cdb_dict_iterate() then writes that pointer back
to *key_r in the caller's slot and only afterwards appends the value
into the same buffer with buffer_append_space_unsafe(). If the total
size (key_len + 1 + value_len + 1) exceeds the buffer's current
allocation (initially 256), the append triggers a realloc on the
default_pool, which moves the backing memory and frees the previous
allocation. The key pointer saved in *key_r is now dangling, and the
caller's next dereference is a heap-use-after-free.

The fix sets *key_r from ctx->buffer->data after the value has been
appended, so it always reflects the buffer's current (post-realloc)
base address. The key is at offset 0, so reading the buffer's data
pointer is sufficient.

Reproduced as a standalone case with AddressSanitizer, which reports
heap-use-after-free on the saved key pointer after the value append
forces the buffer to grow past its initial 256-byte allocation.

2 days agoauth: pam - Allow at most 1024 messages from PAM
Aki Tuomi [Fri, 15 May 2026 06:35:41 +0000 (09:35 +0300)] 
auth: pam - Allow at most 1024 messages from PAM

It is very unlikely that PAM would send more than this.

Co-Authored-By: netliomax25-code <netliomax25@gmail.com>
2 days agodoc/solr-schema-9: Add mandatory attribute class
Brent [Tue, 4 Feb 2025 06:25:57 +0000 (08:25 +0200)] 
doc/solr-schema-9: Add mandatory attribute class

Resolves: ERROR: Error CREATEing SolrCore 'dovecot':
Unable to create core [dovecot] Caused by: [schema.xml] analyzer/tokenizer:
missing mandatory attribute 'class'

2 days agospelling: hexdigest
Josh Soref [Mon, 17 Feb 2025 03:21:49 +0000 (22:21 -0500)] 
spelling: hexdigest

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2 days agospelling: digest
Josh Soref [Mon, 17 Feb 2025 03:22:42 +0000 (22:22 -0500)] 
spelling: digest

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2 days agoglobal: Fix spelling
Josh Soref [Fri, 14 Feb 2025 04:16:17 +0000 (23:16 -0500)] 
global: Fix spelling

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2 days agom4: Fix for systems with signed 32-bit time_t
Paul Howarth [Thu, 26 Jun 2025 09:47:35 +0000 (10:47 +0100)] 
m4: Fix for systems with signed 32-bit time_t

The code and tests have some hard-coded values based on the size of
time_t but they don't take into account whether or not time_t is a
signed value.

On systems such as i686 with time_t as a signed 32-bit integer, the
maximum value is the same as an unsigned 31-bit integer. Tweak the
configure test to treat 32-bit signed as 31 bits.

2 days agolib: use checked arithmetic in string and path length calculations
uwezkhan06 [Sat, 2 May 2026 19:08:20 +0000 (00:38 +0530)] 
lib: use checked arithmetic in string and path length calculations

2 days agolib: fix test-event-filter for systems with 32-bit long
Paul Howarth [Thu, 26 Jun 2025 09:39:40 +0000 (10:39 +0100)] 
lib: fix test-event-filter for systems with 32-bit long

On systems such as i686 with 32-bit long integers, expressions such as

60L * 60 * 1000 * 1000 (3600000000)

overflow the maximum value of 2147483647, causing the test to fail.
This can be fixed by using a "long long" (which is used for intmax_t)
instead, e.g.

60LL * 60 * 1000 * 1000

2 days agolib: panic on nearest_power() overflow with the offending value
Aki Tuomi [Wed, 20 May 2026 12:21:01 +0000 (15:21 +0300)] 
lib: panic on nearest_power() overflow with the offending value

Replace the i_assert() with an i_panic() that reports the input
value, making overflow failures easier to diagnose. Add unit tests
for the boundary input and a fatal test for the overflow case.

Co-Authored-By: uwezkhan06 <uwezkhan053@gmail.com>
4 days agolib-sql: cassandra - Implement get_field_name() and find_field()
Timo Sirainen [Wed, 21 Jan 2026 11:41:31 +0000 (13:41 +0200)] 
lib-sql: cassandra - Implement get_field_name() and find_field()

4 days agolib-sql: cassandra - Use container_of()
Timo Sirainen [Wed, 21 Jan 2026 11:50:48 +0000 (13:50 +0200)] 
lib-sql: cassandra - Use container_of()

11 days agoquota: Fix maildir quota drop to zero after IMAP MOVE/REPLACE
Aki Tuomi [Wed, 13 May 2026 15:33:08 +0000 (15:33 +0000)] 
quota: Fix maildir quota drop to zero after IMAP MOVE/REPLACE

When mailbox_move() or IMAP REPLACE is used with the maildir quota
driver, the source mail expunge is double-counted, causing the quota
to drop to zero.

quota_try_alloc() called quota_alloc_with_size(ctx, size, expunged_size),
which subtracted expunged_size from the destination transaction's
bytes_used. At the same time mail_expunge() on the source/expunged mail
fired quota_mail_expunge(), and the expunge was committed independently
via qbox->expunge_qt in sync_notify. Both deltas commit to the same
quota root, netting -size when size == expunged_size.

Co-Authored: Aleksei Fedorov <aleksei.fedorov@webpros.com>

12 days agolib-storage: Fix lock file collisions when mail_volatile_path is shared
Michael M Slusarz [Fri, 1 May 2026 07:21:19 +0000 (01:21 -0600)] 
lib-storage: Fix lock file collisions when mail_volatile_path is shared

13 days agofts-flatcurve: fix indentation
Michael M Slusarz [Wed, 26 Nov 2025 03:04:49 +0000 (20:04 -0700)] 
fts-flatcurve: fix indentation

13 days agofts-flatcurve: Add support for phrase searching
Michael M Slusarz [Mon, 4 May 2026 22:43:09 +0000 (16:43 -0600)] 
fts-flatcurve: Add support for phrase searching

Fixes issues with false positives on certain phrase searches, as searches
on tokenized pieces are really intended to be used as a limiter on the
full phrase searching as opposed to an indication of full phrase match
on those messages.

Example 1: Exact phrase no-match (the canonical case)

Message body: "abcde fghij"
Search:       BODY "abcd fghi"
Before:       MATCHES (false positive — tokenized "abcd*" AND "fghi*" found)
After:        NO MATCH (correct — exact phrase "abcd fghi" not in body)

Example 2: Exact phrase that should match

Message body: "the quick brown fox"
Search:       BODY "quick brown"
Before:       MATCHES (worked, but for wrong reason — tokenized terms matched)
After:        MATCHES (correct — exact phrase "quick brown" verified by core)

Example 3: Words exist but not as a phrase

Message body: "brown fox quick"
Search:       BODY "quick brown"
Before:       MATCHES (false positive — both words present, just not adjacent)
After:        NO MATCH (correct — "quick brown" doesn't appear as a substring)

Example 4: Single-word split (e.g., dotted word)

Message body: "foo.bar value"
Search:       TEXT "foo.bar"
Before:       NO MATCH (broken — phrase logic incorrectly applied, original
              string "foo.bar" was skipped during token expansion)
After:        MATCHES (correct — single word without spaces is not treated
              as a phrase; "foo.bar" is indexed and matched directly)

Example 5: Multi-word search with one non-phrase word

Message body: "hello world"
Search:       BODY hello "world peace"
Before:       "hello" matched; "world peace" could produce false positives
              from tokenized "world*" AND "peace*"
After:        "hello" matches; "world peace" correctly requires exact phrase

13 days agofts-flatcurve: Extract fts_flatcurve_build_add_maybe_query() into a function
Michael M Slusarz [Mon, 4 May 2026 22:43:06 +0000 (16:43 -0600)] 
fts-flatcurve: Extract fts_flatcurve_build_add_maybe_query() into a function

13 days agofts: Add unit test for search argument parsing
Michael M Slusarz [Mon, 11 May 2026 20:19:54 +0000 (14:19 -0600)] 
fts: Add unit test for search argument parsing

13 days agofts: Add phrase flags to search arguments
Michael M Slusarz [Mon, 11 May 2026 20:19:04 +0000 (14:19 -0600)] 
fts: Add phrase flags to search arguments

Phrase arguments, and the tokenized children are now labeled into
three categories:
- This is the full phrase
- This is a tokenized word of a phrase, and it is the first word
- This is a tokenized word of a phrase

13 days agodoveadm: dump - List all supported types
Michael M Slusarz [Tue, 5 May 2026 05:16:49 +0000 (23:16 -0600)] 
doveadm: dump - List all supported types

Previously, it was only listing the built-in dump types.

2 weeks agolib-storage: fs-iter - Fix double slash in index iteration path
Timo Sirainen [Fri, 8 May 2026 12:23:47 +0000 (12:23 +0000)] 
lib-storage: fs-iter - Fix double slash in index iteration path

2 weeks agolib-storage: maildir++ - Migrate legacy mailbox name escape format on iteration
Timo Sirainen [Thu, 7 May 2026 21:45:01 +0000 (21:45 +0000)] 
lib-storage: maildir++ - Migrate legacy mailbox name escape format on iteration

2 weeks agolib-storage: fs - Migrate legacy mailbox name escape format on iteration
Timo Sirainen [Thu, 7 May 2026 21:42:43 +0000 (21:42 +0000)] 
lib-storage: fs - Migrate legacy mailbox name escape format on iteration

2 weeks agolib-storage: Add mailbox_list_try_migrate_legacy_escape()
Timo Sirainen [Thu, 7 May 2026 21:42:43 +0000 (21:42 +0000)] 
lib-storage: Add mailbox_list_try_migrate_legacy_escape()

Before recent changes, the mailbox_list_escape_name_params() leading-'~' rule
fired on every hierarchy part, so vname "parent/~child" was written to
disk as "parent/\7echild". The new code applies the rule only on the
first part, encoding the same vname as "parent/~child". On-disk
directories written by older Dovecot versions therefore become
inaccessible after upgrade: the lookup constructs the new-format
storage name and stat()s a path that no longer matches.

2 weeks agolib-storage: Add local fname variable
Timo Sirainen [Thu, 7 May 2026 21:40:04 +0000 (21:40 +0000)] 
lib-storage: Add local fname variable

2 weeks agolib-storage: mailbox_name_hdr_encode/decode - Distinguish INBOX from <ns prefix>...
Timo Sirainen [Thu, 30 Apr 2026 14:41:33 +0000 (14:41 +0000)] 
lib-storage: mailbox_name_hdr_encode/decode - Distinguish INBOX from <ns prefix>/INBOX

The box-name index header stored the storage name with per-part unescape,
which collapses <escape>49NBOX to "INBOX". On rebuild from box-name headers,
this made <ns prefix>/INBOX indistinguishable from the regular INBOX, so
list index rebuild restored <ns prefix>/INBOX as INBOX.

Append a backwards compatible flag byte to the box-name header after two
trailing NUL bytes, with MAILBOX_NAME_HDR_FLAG_INBOX_INBOX bit signaling
that the on-disk "INBOX" name actually refers to <ns prefix>/INBOX. The
flag byte is only emitted when at least one bit is set, so old headers
(no flag byte) round-trip unchanged. The decoder strips trailing NUL
padding added by lib-index, then detects the flag suffix unambiguously:
two consecutive NULs at the end never occur in the old format because
the encoder splits on the hierarchy separator and real storage names
contain no empty hierarchy parts.

Old Dovecot versions reading a new-format header will parse the flag
byte as a one-byte trailing hierarchy component. This is acceptable
because old Dovecot never wrote <ns prefix>/INBOX in the first place.

2 weeks agoimapc: Document round-trip requirements for invalid mUTF-7 names
Timo Sirainen [Thu, 30 Apr 2026 09:22:10 +0000 (09:22 +0000)] 
imapc: Document round-trip requirements for invalid mUTF-7 names

Note in the imapc-list.c top-of-file comment that the four name
forms (remote_name, storage_name, vname, fs_name) round-trip
losslessly even for invalid mUTF-7 remote names, but only when
mailbox_list_visible_escape_char is set. With it unset and
mailbox_list_utf8=no, vname falls through to the raw mUTF-7 form
and SELECT round-trips would re-encode literal '&' as "&-",
breaking access to those mailboxes.

This documents the existing behavior; no code change.

2 weeks agolib-storage: Add tests for mailbox_list_escape_name_params() first_part
Timo Sirainen [Thu, 30 Apr 2026 09:06:07 +0000 (09:06 +0000)] 
lib-storage: Add tests for mailbox_list_escape_name_params() first_part

Cover the leading-'~' rule (escaped only when first_part=TRUE), the
per-part dirstart escapes for "." and "..", separator conversion,
and a round-trip property test against
mailbox_list_unescape_name_params() for inputs that look like parts
vs full vnames.

2 weeks agolib-storage: mailbox_list_escape_name_params() - Add first_part parameter
Timo Sirainen [Thu, 30 Apr 2026 09:04:45 +0000 (09:04 +0000)] 
lib-storage: mailbox_list_escape_name_params() - Add first_part parameter

The leading '~' check used to fire whenever the input started with '~'.
That assumed callers always passed the full vname. Since
mailbox_list_default_get_storage_name() and
mailbox_name_hdr_decode_storage_name() now split into hierarchy parts
before escaping, the '~' check would wrongly match the start of any
part - e.g. "foo/~bar" would have its second component escaped as
"+7ebar" even though '~' in the middle of a path has no special
meaning.

Add a first_part parameter. Only when first_part=TRUE do we apply the
leading-'~' escape. Callers operating on parts pass first_part=FALSE
for non-leading parts.

For mailbox_list_default_get_storage_name() also require prefix[0] ==
'\\0' so that when the INBOX/INBOX prefix has been prepended to
storage_name, the first split-part is no longer the very start of the
escaped output.

2 weeks agolib-storage: mailbox_list_unescape_name_params() - Drop unused ns_prefix parameter
Timo Sirainen [Thu, 30 Apr 2026 09:03:08 +0000 (09:03 +0000)] 
lib-storage: mailbox_list_unescape_name_params() - Drop unused ns_prefix parameter

Symmetric to the previous escape_name_params() cleanup. The three
callers (mailbox_list_default_get_vname_part(),
imapc_list_storage_to_remote_name(), imapc_list_fs_to_storage_name())
either pass an empty string or operate on a single hierarchy part
that won't start with the namespace prefix.

No behavior change.

2 weeks agolib-storage: mailbox_list_escape_name_params() - Drop unused ns_prefix parameter
Timo Sirainen [Thu, 30 Apr 2026 09:01:58 +0000 (09:01 +0000)] 
lib-storage: mailbox_list_escape_name_params() - Drop unused ns_prefix parameter

All callers either pass an empty string or pass list->ns->prefix
operating on input where the prefix has already been stripped earlier
(by mailbox_list_vname_prepare() or by splitting into hierarchy parts).
The str_begins(vname, ns_prefix, ...) match was effectively dead.

Drop the parameter. Callers updated: mailbox_list_default_get_storage_name(),
mailbox_name_hdr_decode_storage_name(), imapc_list_remote_to_storage_name(),
imapc_list_storage_to_fs_name().

No behavior change.

2 weeks agolib-storage: Add comments to mailbox name fields
Timo Sirainen [Wed, 28 Jan 2026 13:29:20 +0000 (15:29 +0200)] 
lib-storage: Add comments to mailbox name fields

2 weeks agolib-storage: mailbox_name_hdr_decode_storage_name() - Convert mailbox name header...
Timo Sirainen [Wed, 28 Jan 2026 12:44:23 +0000 (14:44 +0200)] 
lib-storage: mailbox_name_hdr_decode_storage_name() - Convert mailbox name header to raw_parts array first

This will be needed by the following API changes.

2 weeks agolib-storage: mailbox_list_default_get_storage_name() - Convert vname to raw_parts...
Timo Sirainen [Wed, 28 Jan 2026 12:39:31 +0000 (14:39 +0200)] 
lib-storage: mailbox_list_default_get_storage_name() - Convert vname to raw_parts array first

This will be needed by the following API changes.

2 weeks agolib-storage: Support storing <ns prefix>/INBOX in mailbox list index
Timo Sirainen [Mon, 26 Jan 2026 21:58:29 +0000 (23:58 +0200)] 
lib-storage: Support storing <ns prefix>/INBOX in mailbox list index

Since it's identical to the INBOX as name, use a separate header field for
identifying it.

2 weeks agolib-storage: List index rebuild - Add some comments
Timo Sirainen [Tue, 27 Jan 2026 08:45:42 +0000 (10:45 +0200)] 
lib-storage: List index rebuild - Add some comments

2 weeks agolib-storage: Rename mail_storage_list_index_rebuild_mailbox.index_name to storage_name
Timo Sirainen [Tue, 27 Jan 2026 08:07:28 +0000 (10:07 +0200)] 
lib-storage: Rename mail_storage_list_index_rebuild_mailbox.index_name to storage_name

This describes better what it is.

2 weeks agolib-storage: Remove unused mail_storage_list_index_rebuild_mailbox.storage_name
Timo Sirainen [Tue, 27 Jan 2026 08:08:01 +0000 (10:08 +0200)] 
lib-storage: Remove unused mail_storage_list_index_rebuild_mailbox.storage_name

2 weeks agolib-storage: Use escaped ns_prefix/INBOX name also for its child mailboxes
Timo Sirainen [Mon, 26 Jan 2026 23:32:53 +0000 (01:32 +0200)] 
lib-storage: Use escaped ns_prefix/INBOX name also for its child mailboxes

If ns_prefix/INBOX gets renamed, its children should be renamed as well.

2 weeks agolib-storage: mailbox_list_index_node_find_sibling() - Remove const from list parameter
Timo Sirainen [Mon, 26 Jan 2026 21:55:57 +0000 (23:55 +0200)] 
lib-storage: mailbox_list_index_node_find_sibling() - Remove const from list parameter

It doesn't really need to be, and it breaks INDEX_LIST_CONTEXT_REQUIRE()
needed by the following changes.

2 weeks agolib-storage: Fix handling escaped mailbox names in mailbox list index
Timo Sirainen [Mon, 26 Jan 2026 22:09:24 +0000 (00:09 +0200)] 
lib-storage: Fix handling escaped mailbox names in mailbox list index

Code paths using mailbox_list_index_node_get_path() weren't escaping the
mailbox name, breaking some of the functionality for such mailboxes.
This includes:
 * Auto-deleting \Noselect leaf mailboxes
 * Notifying changes to mailbox (IMAP NOTIFY)
 * Storing mailbox GUID in dovecot.list.index

2 weeks agolib-storage: mailbox_list_index_node_get_path() - Replace sep parameter with list
Timo Sirainen [Mon, 26 Jan 2026 22:08:17 +0000 (00:08 +0200)] 
lib-storage: mailbox_list_index_node_get_path() - Replace sep parameter with list

This will be needed by the following changes.

2 weeks agolib-storage: Make mailbox_list_get_escaped_mailbox_name() public
Timo Sirainen [Mon, 26 Jan 2026 22:03:54 +0000 (00:03 +0200)] 
lib-storage: Make mailbox_list_get_escaped_mailbox_name() public

2 weeks agolib-storage: mailbox_list_get_escaped_mailbox_name() - Change raw_name parameter...
Timo Sirainen [Mon, 26 Jan 2026 21:20:47 +0000 (23:20 +0200)] 
lib-storage: mailbox_list_get_escaped_mailbox_name() - Change raw_name parameter to node

2 weeks agolib-storage: List index rebuild - Don't try to restore INBOX as INBOX/INBOX
Timo Sirainen [Tue, 27 Jan 2026 08:36:31 +0000 (10:36 +0200)] 
lib-storage: List index rebuild - Don't try to restore INBOX as INBOX/INBOX

This happened to work for now, but not after the following changes.

2 weeks agolib-storage: mailbox_list_index_update_next() - Simplify updating parent_len
Timo Sirainen [Wed, 28 Jan 2026 12:14:54 +0000 (14:14 +0200)] 
lib-storage: mailbox_list_index_update_next() - Simplify updating parent_len

2 weeks agolib-storage: mailbox_list_index_update_next() - Reorder code to simplify
Timo Sirainen [Wed, 28 Jan 2026 12:04:21 +0000 (14:04 +0200)] 
lib-storage: mailbox_list_index_update_next() - Reorder code to simplify

2 weeks agolib-imap: imap-parser.h - Fix typo in comment
Timo Sirainen [Wed, 29 Apr 2026 14:58:53 +0000 (17:58 +0300)] 
lib-imap: imap-parser.h - Fix typo in comment

2 weeks agolib-imap: Fix imap_parser_params.list_count_limit to actually work
Timo Sirainen [Mon, 27 Apr 2026 14:40:46 +0000 (17:40 +0300)] 
lib-imap: Fix imap_parser_params.list_count_limit to actually work

The previous fix in d0f67b52914565a35f3817335ab9633cb291513c was
accidentally limiting the number of ')', not the number of '('.

2 weeks agologin-common: Emit proxy_session_finished and new _started event when client is redir...
Timo Sirainen [Tue, 5 May 2026 21:15:22 +0000 (21:15 +0000)] 
login-common: Emit proxy_session_finished and new _started event when client is redirected

When LOGIN_PROXY_FAILURE_TYPE_AUTH_REDIRECT was handled, the disconnect
event chain never produced an error_code=proxy_dest_redirected entry.
Fire a new proxy_session_finished event with this error_code and start
a new proxy_session_started for the new destination.

2 weeks agologin-proxy: Set destination event fields in login_proxy_set_destination()
Timo Sirainen [Tue, 5 May 2026 21:14:04 +0000 (21:14 +0000)] 
login-proxy: Set destination event fields in login_proxy_set_destination()

Move dest_host, dest_ip and dest_port event_add_*() calls from
login_proxy_new() into login_proxy_set_destination(). This ensures the
fields stay in sync.

2 weeks agoimap-login: Reject duplicate MULTIPLEX from backend
Timo Sirainen [Wed, 6 May 2026 15:19:16 +0000 (15:19 +0000)] 
imap-login: Reject duplicate MULTIPLEX from backend

If a buggy backend IMAP server sends "* MULTIPLEX 0" twice, the second
parse call re-entered login_proxy_multiplex_input_start() and crashed
on the multiplex_orig_input==NULL assert. Detect the duplicate and
fail the proxy connection with a protocol error instead.

2 weeks agologin-common: Add login_proxy_multiplex_input_started()
Timo Sirainen [Wed, 6 May 2026 15:19:13 +0000 (15:19 +0000)] 
login-common: Add login_proxy_multiplex_input_started()

Returns whether login_proxy_multiplex_input_start() has already been
called on the proxy. Lets callers detect a duplicate MULTIPLEX
notification from a buggy backend instead of triggering the
multiplex_orig_input==NULL assert.

2 weeks agolib-var-expand: Reject empty separator in fn_index_common()
Aki Tuomi [Mon, 4 May 2026 05:33:56 +0000 (08:33 +0300)] 
lib-var-expand: Reject empty separator in fn_index_common()

Otherwise it will end up in infinite loop.

2 weeks agolib-auth: scram - Remove trailing whitespace from file
Karl Fleischmann [Fri, 1 May 2026 07:13:18 +0000 (09:13 +0200)] 
lib-auth: scram - Remove trailing whitespace from file

2 weeks agolib-auth: scram - Ensure client proof field syntax before validation
Karl Fleischmann [Fri, 1 May 2026 07:11:15 +0000 (09:11 +0200)] 
lib-auth: scram - Ensure client proof field syntax before validation

2 weeks agolib-auth: scram - Add test to ensure invalid client proof is rejected
Karl Fleischmann [Tue, 28 Apr 2026 11:41:12 +0000 (13:41 +0200)] 
lib-auth: scram - Add test to ensure invalid client proof is rejected

2 weeks agofts-flatcurve: Cleanups in fts_backend_flatcurve_delete_dir()
Michael M Slusarz [Fri, 24 Apr 2026 04:33:47 +0000 (22:33 -0600)] 
fts-flatcurve: Cleanups in fts_backend_flatcurve_delete_dir()

Ensure that error_r is not NULL.
Remove unnecessary else directive.

2 weeks agofts-flatcurve: Clean up FTS directory on mailbox deletion
Michael M Slusarz [Fri, 24 Apr 2026 04:33:15 +0000 (22:33 -0600)] 
fts-flatcurve: Clean up FTS directory on mailbox deletion

This code is only needed for Maildir. dbox handles FTS cleanup
already because it can just recursively delete the entire index
directory natively. Maildir (for safety reasons) can only delete
directories that appear in the "is_internal_name" list.

2 weeks agolib-storage: Allow is_internal_name() to be extended
Michael M Slusarz [Mon, 4 May 2026 19:56:44 +0000 (13:56 -0600)] 
lib-storage: Allow is_internal_name() to be extended

2 weeks agoauth: Fix stale cache entry blocking auth after password change in worker path
Fred Morcos [Thu, 30 Apr 2026 14:44:27 +0000 (16:44 +0200)] 
auth: Fix stale cache entry blocking auth after password change in worker path

When passdb cache verification runs on an auth worker, a successful
prior login plus a subsequent password change leaves a stale cached
password. The non-worker code path already handles this: if the
cached password mismatches and the entry's last_success flag (or
neg_expired) indicates the cache is likely stale, fall back to a
fresh passdb lookup. The worker callback was missing this handling,
so users would fail to authenticate until the cache entry expired.

After the worker returns a PASSWORD_MISMATCH, re-lookup the cache
node and apply the same passdb_cache_use_password_mismatch() rule
to decide whether to invoke the fallback. The node pointer cannot
be carried across the worker round-trip (see auth_cache_node
lifetime), so the lookup is redone here. orig_cache_result is
preserved so the re-lookup does not clobber the request's recorded
cache result.

If the re-lookup misses because the entry was evicted while the
worker was busy, fall back unconditionally instead of delivering
the mismatch as-is: a password change would otherwise be reported
as a mismatch instead of being retried, and the cached evidence
that would have driven the stale-cache rule no longer exists, so
an extra fresh lookup is the right behavior.

2 weeks agoauth: Convert passdb_cache_verify_plain() to continuation-passing style
Fred Morcos [Thu, 30 Apr 2026 15:34:55 +0000 (17:34 +0200)] 
auth: Convert passdb_cache_verify_plain() to continuation-passing style

Change passdb_cache_verify_plain() from a bool-returning function with
an out-param to one that always invokes a continuation: either it
finishes the verification itself (cache hit, negative entry, etc.)
or it invokes the supplied fallback callback (cache miss, password
mismatch with stale-cache eligibility, no cache configured).

Callers no longer need to handle the result themselves; the helper
decides and dispatches. This unifies how cache hits and misses are
handed back into the auth flow and is preparation for fixing the
worker path's stale-cache handling.

Add auth_request_verify_plain_internal_failure() as the fallback
callback for the INTERNAL_FAILURE/expired-cache path in
auth_request_verify_plain_passdb_callback(). The existing
auth_request_verify_plain_passdb() helper is reused as the fallback
for the initial verify path.

No behavior change.

2 weeks agoauth: Extract auth_request_verify_plain_passdb() helper
Fred Morcos [Thu, 30 Apr 2026 15:34:55 +0000 (17:34 +0200)] 
auth: Extract auth_request_verify_plain_passdb() helper

Move the post-cache-check passdb dispatch (state transition,
wanted_credentials_scheme reset, blocking/direct iface call) out of
auth_request_default_verify_plain_continue() into a static helper. Pure
refactoring with no behavior change.

2 weeks agoauth: Rename auth_request_verify_plain_callback() to auth_request_verify_plain_passdb...
Fred Morcos [Thu, 30 Apr 2026 15:31:47 +0000 (17:31 +0200)] 
auth: Rename auth_request_verify_plain_callback() to auth_request_verify_plain_passdb_callback()

Pure rename. The callback is invoked from passdb verification paths
(both blocking-worker and direct), so the new name better describes
where it sits in the call chain and disambiguates it from
auth_request_verify_plain_callback_finish().

2 weeks agoauth: Extract password mismatch helper
Fred Morcos [Thu, 30 Apr 2026 13:20:27 +0000 (15:20 +0200)] 
auth: Extract password mismatch helper

2 weeks agoauth: Fix warning about incorrect argument name
Fred Morcos [Tue, 14 Apr 2026 11:55:00 +0000 (13:55 +0200)] 
auth: Fix warning about incorrect argument name

2 weeks agolib-smtp: Ignore test.out in test-smtp-payload
Aki Tuomi [Sat, 2 May 2026 17:32:43 +0000 (20:32 +0300)] 
lib-smtp: Ignore test.out in test-smtp-payload

3 weeks agolog: Fix memory leak at deinit
Timo Sirainen [Sat, 2 May 2026 18:37:35 +0000 (21:37 +0300)] 
log: Fix memory leak at deinit

3 weeks agopush-notification: ox - Fix use-after-free crash during DNS lookup
Timo Sirainen [Tue, 28 Apr 2026 16:17:32 +0000 (19:17 +0300)] 
push-notification: ox - Fix use-after-free crash during DNS lookup

This is a similar fix as 3d0aea564e7f3d0763c290f0bc86c9483cb6dab7 for
fts-solr and 4fd663ac856f4517221e278f5ca1b5dbe282c3ba for fts-tika.

3 weeks agolib-event: Add event_get_global_root()
Timo Sirainen [Fri, 24 Apr 2026 19:52:41 +0000 (19:52 +0000)] 
lib-event: Add event_get_global_root()

Returns the bottom-most (oldest pushed) event on the global event
stack, or the current global event if the stack is empty. Lets
plugins annotate the outermost active caller's event from within a
nested global event context.

3 weeks agoimap: Add [THROTTLED] response code to tagged replies
Timo Sirainen [Fri, 24 Apr 2026 19:42:55 +0000 (19:42 +0000)] 
imap: Add [THROTTLED] response code to tagged replies

When a plugin marks cmd->global_event with a positive integer
"throttled_any" field during command execution, the tagged response
is prefixed with [THROTTLED] resp-code (skipped when the reply text
already carries a resp-code per RFC 3501) and gets a
"(throttled N.NNN secs)" annotation before the timing stats. The
annotation is always added when throttled, so clients that cannot
act on the resp-code still see throttling in the reply text.

3 weeks agolib: p_strarray_dup() - Harden against integer overflows
Timo Sirainen [Tue, 21 Apr 2026 20:14:04 +0000 (20:14 +0000)] 
lib: p_strarray_dup() - Harden against integer overflows

3 weeks agolib: p_strsplit_tabescaped_inplace() - Use p_new()
uwezkhan06 [Tue, 21 Apr 2026 20:27:36 +0000 (20:27 +0000)] 
lib: p_strsplit_tabescaped_inplace() - Use p_new()

3 weeks agolib: Use p_realloc_type() where possible
uwezkhan06 [Tue, 21 Apr 2026 20:27:38 +0000 (20:27 +0000)] 
lib: Use p_realloc_type() where possible

3 weeks agolib: array - Use MALLOC_MULTIPLY() for index arithmetic
uwezkhan06 [Tue, 21 Apr 2026 20:24:27 +0000 (20:24 +0000)] 
lib: array - Use MALLOC_MULTIPLY() for index arithmetic

3 weeks agolib: buffer - Add buffer_{write,append,insert}_array() helpers
uwezkhan06 [Tue, 21 Apr 2026 20:24:22 +0000 (20:24 +0000)] 
lib: buffer - Add buffer_{write,append,insert}_array() helpers

3 weeks agoconfig: Add more supported versions
Timo Sirainen [Fri, 1 May 2026 16:48:03 +0000 (19:48 +0300)] 
config: Add more supported versions

3 weeks agofts: build-mail - Fix address header indexing for RFC 2047 encoded-words
Timo Sirainen [Fri, 17 Apr 2026 19:33:32 +0000 (19:33 +0000)] 
fts: build-mail - Fix address header indexing for RFC 2047 encoded-words

The header value reaching fts_build_mail_header() was already RFC 2047
decoded by message_decoder, so passing it to message_address_parse()
meant decoded display name characters were reinterpreted as RFC 5322
syntax. For example:

  From: =?UTF-8?B?VGVzdHVzZXIgKEV4YW1wbGUp?= <user@example.com>

decodes to "Testuser (Example)" and "(Example)" was then silently dropped as
an RFC 5322 comment. Similarly, display names containing characters
like '[' made parse_name_addr() fail, leaving neither the display name
nor the email address indexed.

Enable MESSAGE_DECODER_FLAG_RAW_ADDRESS_HEADERS so that address headers
arrive with encoded-words intact, parse the raw value, write the
normalised address, and then decode the result to UTF-8 before handing
it to the FTS backend.

3 weeks agolib-mail: message-decoder - Add flag to skip RFC 2047 decoding for address headers
Timo Sirainen [Fri, 17 Apr 2026 19:32:23 +0000 (19:32 +0000)] 
lib-mail: message-decoder - Add flag to skip RFC 2047 decoding for address headers

Add MESSAGE_DECODER_FLAG_RAW_ADDRESS_HEADERS. When set, address headers
(From, To, Cc, etc.) are passed through with their raw bytes intact
instead of having encoded-words decoded to UTF-8. This lets callers
feed the raw value to message_address_parse() so that decoded display
name characters like '(' or '[' are not reinterpreted as RFC 5322
comments or other specials during address parsing.

3 weeks agoacl: Assert-crash if ACL identifier is invalid before writing it
Timo Sirainen [Wed, 22 Apr 2026 12:45:00 +0000 (15:45 +0300)] 
acl: Assert-crash if ACL identifier is invalid before writing it

It should have been checked earlier already.

3 weeks agoimap-acl: Fail if ACL identifier is invalid
Timo Sirainen [Wed, 22 Apr 2026 12:44:24 +0000 (15:44 +0300)] 
imap-acl: Fail if ACL identifier is invalid

Reject invalid identifiers early in imap_acl_identifier_parse() using
acl_id_is_valid(). This prevents CR/LF injection and rejects identifiers
that are too long, contain control characters or are not valid UTF-8.

3 weeks agoacl: Add acl_id_is_valid()
Timo Sirainen [Wed, 22 Apr 2026 12:43:58 +0000 (15:43 +0300)] 
acl: Add acl_id_is_valid()

Returns TRUE if the ACL identifier string is at most ACL_ID_MAX_LEN
(1024) bytes long, contains no control characters and is valid UTF-8.

3 weeks agologin-common: Only accept base64 in sasl
Aki Tuomi [Wed, 8 Apr 2026 08:33:11 +0000 (11:33 +0300)] 
login-common: Only accept base64 in sasl

3 weeks agolib-storage: Prevent non-atom SEARCH keywords from causing IMAP command injection
Timo Sirainen [Sun, 12 Apr 2026 20:27:01 +0000 (23:27 +0300)] 
lib-storage: Prevent non-atom SEARCH keywords from causing IMAP command injection

If a non-atom keyword is found, convert the SEARCH parameter to NOT ALL.

3 weeks agolib-storage: Fail if IMAP SEARCH keyword is not atom
Timo Sirainen [Sun, 12 Apr 2026 20:25:31 +0000 (23:25 +0300)] 
lib-storage: Fail if IMAP SEARCH keyword is not atom

3 weeks agolib-imap: Add imap_str_is_atom()
Timo Sirainen [Sun, 12 Apr 2026 20:24:47 +0000 (23:24 +0300)] 
lib-imap: Add imap_str_is_atom()

3 weeks agolib-var-expand: Reset safe state when transfer is unset
Aki Tuomi [Sun, 29 Mar 2026 16:33:45 +0000 (19:33 +0300)] 
lib-var-expand: Reset safe state when transfer is unset

Otherwise unsafe content is treated safe.

3 weeks agologin-common: Translate haproxy ssl_client_cert into VALID_CLIENT_CERT
Timo Sirainen [Thu, 23 Apr 2026 12:35:17 +0000 (12:35 +0000)] 
login-common: Translate haproxy ssl_client_cert into VALID_CLIENT_CERT

When haproxy terminates TLS for the end client and reports via the
PP2_TYPE_SSL TLV that a client certificate was presented and
successfully verified, propagate this to the auth request as
AUTH_REQUEST_FLAG_VALID_CLIENT_CERT. Without this, settings such as
auth_ssl_require_client_cert cannot be used with plaintext haproxy
listeners, even though haproxy has performed certificate verification
on the dovecot operator's behalf.

Add a haproxy_ssl_client_cert field to struct client that mirrors the
master_service_connection_haproxy.ssl_client_cert field, and use it
alongside the existing ssl_iostream check in client_get_auth_flags().

3 weeks agolib-master: Fill master_service_connection_haproxy.ssl_client_cert flag
Timo Sirainen [Thu, 23 Apr 2026 10:51:52 +0000 (10:51 +0000)] 
lib-master: Fill master_service_connection_haproxy.ssl_client_cert flag

It's TRUE if HAProxy verified the client certificate was valid.
Previously the field was always set to FALSE.

3 weeks agolib-master: haproxy - Honor PP2 SSL TLV verify and client cert flags
Timo Sirainen [Thu, 23 Apr 2026 10:44:11 +0000 (10:44 +0000)] 
lib-master: haproxy - Honor PP2 SSL TLV verify and client cert flags

Previously the parser ignored both the verify field and the
PP2_CLIENT_CERT_CONN / PP2_CLIENT_CERT_SESS bits in the client byte
of the PP2_TYPE_SSL TLV, and unconditionally copied the client
certificate common name into the connection. This meant that a
common name reported by HAProxy was trusted even when HAProxy itself
had reported a verification failure (verify != 0).

Set ssl_client_cert from the cert presence bits, and only trust the
common name when a client certificate was presented and verified
successfully. When verify is non-zero, the certificate sub-TLVs are
ignored.

3 weeks agolib-master: haproxy - Read PP2 SSL TLV verify field as big-endian
Timo Sirainen [Thu, 23 Apr 2026 10:43:28 +0000 (10:43 +0000)] 
lib-master: haproxy - Read PP2 SSL TLV verify field as big-endian

The PROXY protocol v2 specification does not explicitly state the
endianness of the verify field in the PP2_TYPE_SSL TLV, but the
reference HAProxy implementation transmits it in network byte order
via htonl().

This doesn't really matter, because the field is checked either as
0 or non-0 in the next commit as well.

3 weeks agolib: file_create_locked() - Make sure locked file isn't a symlink
Timo Sirainen [Wed, 29 Apr 2026 15:13:02 +0000 (18:13 +0300)] 
lib: file_create_locked() - Make sure locked file isn't a symlink

Since this is used for files that are auto-created, there's likely no reason
for it to support the file being a symlink. So its behavior is now safer by
not allowing locking symlinks.

3 weeks agomdbox: Create files with O_NOFOLLOW
Timo Sirainen [Mon, 27 Apr 2026 22:20:20 +0000 (01:20 +0300)] 
mdbox: Create files with O_NOFOLLOW

Forgotten in 0b13dba538c1b397fd38de8d312a75fc560adada

3 weeks agoanvil: Introduce struct anvil_command for array dispatch
Timo Sirainen [Mon, 27 Apr 2026 22:12:50 +0000 (22:12 +0000)] 
anvil: Introduce struct anvil_command for array dispatch

Register all anvil commands in an array and dispatch them with a
for-loop. The connection type allowed for each command is now declared
in the array entry, and the type check happens in the generic
dispatcher rather than in each command handler.

3 weeks agoanvil: Make connection type explicit per command
Timo Sirainen [Mon, 27 Apr 2026 22:10:52 +0000 (22:10 +0000)] 
anvil: Make connection type explicit per command

Each command handler now explicitly checks that the connection type is
allowed for that command. This replaces the implicit 'AUTH_PENALTY only
allows PENALTY-*' check in the dispatcher and the special-case KILL
check.

3 weeks agoanvil: Move command handlers into separate functions
Timo Sirainen [Mon, 27 Apr 2026 22:09:02 +0000 (22:09 +0000)] 
anvil: Move command handlers into separate functions

Each command in anvil_connection_request() now has its own static
handler function. The dispatcher only does the lookup and forwards
parameters.

3 weeks agologin-common, lmtp: Switch LOOKUP queries to anvil-connect-limit socket
Timo Sirainen [Mon, 27 Apr 2026 22:31:10 +0000 (22:31 +0000)] 
login-common, lmtp: Switch LOOKUP queries to anvil-connect-limit socket

LOOKUP commands are now only accepted on connections of type
ANVIL_CONNECTION_TYPE_CONNECT_LIMIT. Connect to the dedicated
anvil-connect-limit socket instead of the generic anvil admin socket.

3 weeks agoanvil: Add ANVIL_CONNECTION_TYPE_CONNECT_LIMIT and anvil-connect-limit listener
Timo Sirainen [Mon, 27 Apr 2026 22:07:38 +0000 (22:07 +0000)] 
anvil: Add ANVIL_CONNECTION_TYPE_CONNECT_LIMIT and anvil-connect-limit listener

This will be used to restrict LOOKUP commands to a dedicated socket,
keeping the admin socket reserved for admin commands.

3 weeks agoanvil: Rename ANVIL_CONNECTION_TYPE_MASTER to ANVIL_CONNECTION_TYPE_SHARED_FIFO
Timo Sirainen [Mon, 27 Apr 2026 22:04:53 +0000 (22:04 +0000)] 
anvil: Rename ANVIL_CONNECTION_TYPE_MASTER to ANVIL_CONNECTION_TYPE_SHARED_FIFO

This connection type is the shared FIFO from the master process that all
services use to send CONNECT, DISCONNECT and KILL commands. Rename
accordingly.

3 weeks agoanvil: Rename ANVIL_CONNECTION_TYPE_DEFAULT to ANVIL_CONNECTION_TYPE_ADMIN
Timo Sirainen [Mon, 27 Apr 2026 22:04:31 +0000 (22:04 +0000)] 
anvil: Rename ANVIL_CONNECTION_TYPE_DEFAULT to ANVIL_CONNECTION_TYPE_ADMIN

This connection type handles admin commands, so name it accordingly.