Re: courier-imap unable to open INBOX

From: Guido Falsi <madpilot_at_FreeBSD.org>
Date: Sun, 16 Feb 2025 17:20:49 UTC
On 16/02/25 14:39, Benjamin Lutz wrote:
> Hello,
> 
> Recently I encountered a problem with courier-imap an two different 
> machines. When trying to open the INBOX, courier-imap's imapd would 
> answer with:
> 
>      NO Unable to open this mailbox.
> 
> The existance or absence of the problem can be quickly tested with:
> 
>      $ echo 'a SELECT INBOX' | imapd ~/Maildir
> 
> I'm running FreeBSD-13.4 and 14.2 on the affected machines, and courier- 
> imap is installed via ports, the only enabled CONFIG options are INOTIFY 
> and IPV6.
> 
> The first thing I tried is to recompile the port and all dependencies, 
> but that didn't solve the problem.

Hi!

I've been experiencing issues with imap too, as soon as I updated 
libunistring, reported it here:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=283588

downgrading libunistring to 1.2 "fixed" the issue for me. So I suspect 
this is somewhat related, but have not been able to diagnose the issue 
so far.

Also, up to now I was not even sure it was not a local issue I was the 
only one having!

> 
> So I dug into courier-imap's source code, finally coming to this line in 
> maildircreate.c:149:
> 
>      if (stat( info->tmpname, &stat_buf) == 0)
> 
> What the code is trying to do here is to create a temporary file; it 
> runs stat(2) on info->tmpname, expecting a -1 return value and errno set 
> to ENOENT, because the file shouldn't currently exist. However, errno is 
> not set to ENOENT, which finally results in the "NO Unable to open this 
> mailbox." error.
> 
> In order to better understand it, I built courier-imap with debugging 
> flags and added some debugging code around the line above:
> 
>      errno=-999;
>      int stat_retval=stat( info->tmpname, &stat_buf);
>      fprintf(stderr, "stat=%p, stat(%p, %p), stat_retval=%d, errno=%d,
>          strerror(errno)=%s\n", stat, info->tmpname, &stat_buf,
>          stat_retval, errno, strerror(errno));
>      if (stat_retval == 0)
> 
> When SELECTing the INBOX now, I get:
> 
>      stat=0x823bc4f70, stat(0x2f67a4269000, 0x820949b40), stat_retval=-1,
>          errno=-999, strerror(errno)=Unknown error: -999
>      a NO Unable to open this mailbox.
> 
> So errno isn't changed by stat(2) (confirmed with other values than 
> -999). This has me rather perplexed. How can a stat(2) call not set 
> errno? As far as I can tell using GDB, that stat() call really is a call 
> into libc, not some other function that might shadow stat(2).
> 
> I've extracted maildircreate.c into a separate project to build a 
> minimal test, but when I just call the function in question 
> (maildir_tmpcreate_fd, which the line above is from), then stat(2) works 
> as expected, i.e. errno is set to 2.
> 
> Can anyone give me some explanations for the observed behavior? Or even 
> just some ideas for analyzing it further?
> 
> The current stop-gap measure I've implemented to make courier-imap work 
> again is the following patch:
> 
>      --- libs/maildir/maildircreate.c.orig   2022-05-23
>          11:00:05.000000000 +0200
>      +++ libs/maildir/maildircreate.c        2025-02-14
>          22:19:39.434539000 +0100
>      @@ -146,6 +146,7 @@
>              strcat(info->tmpname, hostname);
>              strcat(info->tmpname, len_buf);
> 
>      +       errno=ENOENT;
>              if (stat( info->tmpname, &stat_buf) == 0)
>              {
>                      maildir_tmpcreate_free(info);
> 
> But obviously, that's not exactly a reliable solution.
> 

As I said, reverting libunistring to 1.2 "fixes" it for me, so it could 
be libunistring interfering in some way with stat?


-- 
Guido Falsi <madpilot@FreeBSD.org>