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 ...
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 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 @@
char *name;
SM_MBDB_T *user;
{
struct passwd *pw;
+#ifdef _FFR_GETPWNAM_R
+ struct passwd pwres;
+ char pwbuf[1024];
+#endif
#ifdef HESIOD
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
{
@@ -327,31 +331,16 @@
return EX_NOUSER;
}
#endif /* HESIOD */
- errno = 0;
+#ifdef _FFR_GETPWNAM_R
+ if (getpwnam_r(name, &pwres, pwbuf, sizeof(pwbuf), &pw) != 0)
+ return EX_TEMPFAIL;
+#else
pw = getpwnam(name);
+#endif
if (pw == NULL)
- {
-#if 0
- /*
- ** 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;
- default:
- return EX_TEMPFAIL;
- }
-#endif /* 0 */
return EX_NOUSER;
- }
sm_mbdb_frompw(user, pw);
return EX_OK;
}
--
Emmanuel Dreyfus
http://hcpnet.free.fr/pubz
manu@netbsd.org