This is a discussion on Fixing getpwnam() unreliability - SendMail ; Hello On local delivery, sendmail uses getpwnam() to lookup the recipient's home directory (if F=w in Mlocal). This is a source of unreliability, as getpwnam() does not distinguigh an error and an unexistant user. In both situations, NULL is returned ...
On local delivery, sendmail uses getpwnam() to lookup the recipient's home
directory (if F=w in Mlocal).
This is a source of unreliability, as getpwnam() does not distinguigh an error
and an unexistant user. In both situations, NULL is returned and errno is not
sed (SUSv2 specify it that way, so this is not an OS-specific implementation
bug in getpwnam()).
So if you use nss_ldap for your local user directory, when the LDAP server
gets unreachable, sendmail wil start bouncing mail, telling the recipient does
not exist. The right behavior would be to tempfail. The same scenario can
happen with Hesiod or NIS.
The solution is to use getpwnam_r(), as this function is able to distinguish
an inexistant user and an error. Below is a patch that should fix it (not
tested yet, I'd like to have feedback about the issue before moving forward,
so that I don't waste time on a patch that will never get integrated).
If this does not get fixed, then the only workaround is to remove F=w in
Mlocal, and rely on the local mailer to detect the problem correctly, which is
only possible if it uses getpwnam_r() and not getpwnam(). But this workaround
means loosing various features.
--- libsm/mbdb.c.orig 2003-12-10 04:19:07.000000000 +0100
+++ libsm/mbdb.c 2008-11-09 17:02:31.000000000 +0100
@@ -313,8 +313,12 @@
struct passwd *pw;
+ struct passwd pwres;
+ char pwbuf;
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
@@ -327,31 +331,16 @@
#endif /* HESIOD */
- errno = 0;
+ if (getpwnam_r(name, &pwres, pwbuf, sizeof(pwbuf), &pw) != 0)
+ return EX_TEMPFAIL;
pw = getpwnam(name);
if (pw == NULL)
- ** getpwnam() isn't advertised as setting errno.
- ** In fact, under FreeBSD, non-root getpwnam() on
- ** non-existant users returns NULL with errno = EPERM.
- ** This test won't work.
- switch (errno)
- case 0:
- return EX_NOUSER;
- case EIO:
- return EX_OSERR;
- return EX_TEMPFAIL;
-#endif /* 0 */