/*
* Copyright (c) 2001-2003,2009 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <stdlib.h>
#include <setjmp.h>
#include <unistd.h>
#include <sm/errstring.h>
# ifdef EX_OK
# endif /* EX_OK */
#include <sm/sysexits.h>
#if LDAPMAP
# if _LDAP_EXAMPLE_
# endif /* _LDAP_EXAMPLE_ */
#endif /* LDAPMAP */
typedef struct
{
char *mbdb_typename;
static int mbdb_pw_initialize __P((char *));
static void mbdb_pw_terminate __P((void));
#if LDAPMAP
# if _LDAP_EXAMPLE_
static int mbdb_ldap_initialize __P((char *));
static void mbdb_ldap_terminate __P((void));
# endif /* _LDAP_EXAMPLE_ */
#endif /* LDAPMAP */
{
#if LDAPMAP
# if _LDAP_EXAMPLE_
# endif /* _LDAP_EXAMPLE_ */
#endif /* LDAPMAP */
};
/*
** SM_MBDB_INITIALIZE -- specify which mailbox database to use
**
** If this function is not called, then the "pw" implementation
** is used by default; this implementation uses getpwnam().
**
** Parameters:
** mbdb -- Which mailbox database to use.
** The argument has the form "name" or "name.arg".
** "pw" means use getpwnam().
**
** Results:
** EX_OK on success, or an EX_* code on failure.
*/
int
char *mbdb;
{
int err;
char *name;
char *arg;
SM_MBDB_TYPE_T *t;
else
{
++arg;
}
{
{
if (t->mbdb_initialize != NULL)
SmMbdbType = t;
return err;
}
}
return EX_UNAVAILABLE;
}
/*
** SM_MBDB_TERMINATE -- terminate connection to the mailbox database
**
** Because this function closes any cached file descriptors that
** are being held open for the connection to the mailbox database,
** it should be called for security reasons prior to dropping privileges
** and execing another process.
**
** Parameters:
** none.
**
** Results:
** none.
*/
void
{
}
/*
** SM_MBDB_LOOKUP -- look up a local mail recipient, given name
**
** Parameters:
** name -- name of local mail recipient
** user -- pointer to structure to fill in on success
**
** Results:
** On success, fill in *user and return EX_OK.
** If the user does not exist, return EX_NOUSER.
** If a temporary failure (eg, a network failure) occurred,
** return EX_TEMPFAIL. Otherwise return EX_OSERR.
*/
int
char *name;
{
return ret;
}
/*
** SM_MBDB_FROMPW -- copy from struct pw to SM_MBDB_T
**
** Parameters:
** user -- destination user information structure
** pw -- source passwd structure
**
** Results:
** none.
*/
void
{
sizeof(user->mbdb_fullname));
sizeof(user->mbdb_homedir));
sizeof(user->mbdb_shell));
}
/*
** SM_PWFULLNAME -- build full name of user from pw_gecos field.
**
** This routine interprets the strange entry that would appear
** in the GECOS field of the password file.
**
** Parameters:
** gecos -- name to build.
** user -- the login name of this user (for &).
** buf -- place to put the result.
** buflen -- length of buf.
**
** Returns:
** none.
*/
{
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33,
99, 80, 36, 89, 124, 36, 34, 99, 97, 60, 45, 45, 114, 45, 111, 42,
50, 51, 39, 117, 80, 46, 44, 49, 111, 62, 42, 42, 42, 63, 65, 65,
65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, 79,
79, 79, 79, 79, 88, 79, 85, 85, 85, 85, 89, 80, 66, 97, 97, 97, 97,
97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, 100, 110,
111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, 112, 121
};
#endif /* _FFR_HANDLE_ISO8859_GECOS */
void
register char *gecos;
char *user;
char *buf;
{
register char *p;
if (*gecos == '*')
gecos++;
/* copy gecos, interpolating & to be full name */
{
{
/* buffer overflow -- just use login name */
return;
}
if (*p == '&')
{
/* interpolate full name */
}
else
{
if ((unsigned char) *p >= 128)
else
#endif /* _FFR_HANDLE_ISO8859_GECOS */
*bp++ = *p;
}
}
*bp = '\0';
}
/*
*/
/*
** MBDB_PW_INITIALIZE -- initialize getpwnam() version
**
** Parameters:
** arg -- unused.
**
** Results:
** EX_OK.
*/
/* ARGSUSED0 */
static int
char *arg;
{
return EX_OK;
}
/*
** MBDB_PW_LOOKUP -- look up a local mail recipient, given name
**
** Parameters:
** name -- name of local mail recipient
** user -- pointer to structure to fill in on success
**
** Results:
** On success, fill in *user and return EX_OK.
** Failure: EX_NOUSER.
*/
static int
char *name;
{
#ifdef HESIOD
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
{
char *p;
for (p = name; *p != '\0'; p++)
break;
if (*p == '\0')
return EX_NOUSER;
}
#endif /* HESIOD */
errno = 0;
{
/*
** Only enable this code iff
** user unknown <-> getpwnam() == NULL && errno == 0
** (i.e., errno unchanged); see the POSIX spec.
*/
if (errno != 0)
return EX_TEMPFAIL;
#endif /* _FFR_USE_GETPWNAM_ERRNO */
return EX_NOUSER;
}
return EX_OK;
}
/*
** MBDB_PW_TERMINATE -- terminate connection to the mailbox database
**
** Parameters:
** none.
**
** Results:
** none.
*/
static void
{
endpwent();
}
#if LDAPMAP
# if _LDAP_EXAMPLE_
/*
** LDAP example implementation based on RFC 2307, "An Approach for Using
** LDAP as a Network Information Service":
**
** ( nisSchema.1.0 NAME 'uidNumber'
** DESC 'An integer uniquely identifying a user in an
** administrative domain'
** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
**
** ( nisSchema.1.1 NAME 'gidNumber'
** DESC 'An integer uniquely identifying a group in an
** administrative domain'
** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
**
** ( nisSchema.1.2 NAME 'gecos'
** DESC 'The GECOS field; the common name'
** EQUALITY caseIgnoreIA5Match
** SUBSTRINGS caseIgnoreIA5SubstringsMatch
** SYNTAX 'IA5String' SINGLE-VALUE )
**
** ( nisSchema.1.3 NAME 'homeDirectory'
** DESC 'The absolute path to the home directory'
** EQUALITY caseExactIA5Match
** SYNTAX 'IA5String' SINGLE-VALUE )
**
** ( nisSchema.1.4 NAME 'loginShell'
** DESC 'The path to the login shell'
** EQUALITY caseExactIA5Match
** SYNTAX 'IA5String' SINGLE-VALUE )
**
** ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
** DESC 'Abstraction of an account with POSIX attributes'
** MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
** MAY ( userPassword $ loginShell $ gecos $ description ) )
**
*/
# ifndef MBDB_LDAP_FILTER
# endif /* MBDB_LDAP_FILTER */
# ifndef MBDB_DEFAULT_LDAP_BASEDN
# endif /* MBDB_DEFAULT_LDAP_BASEDN */
# ifndef MBDB_DEFAULT_LDAP_SERVER
# endif /* MBDB_DEFAULT_LDAP_SERVER */
/*
** MBDB_LDAP_INITIALIZE -- initialize LDAP version
**
** Parameters:
** arg -- LDAP specification
**
** Results:
** EX_OK on success, or an EX_* code on failure.
*/
static int
char *arg;
{
/* Only want one match */
/* interpolate new ldap_base and ldap_host from arg if given */
{
char *new;
char *sep;
return EX_TEMPFAIL;
{
*sep++ = '\0';
}
}
return EX_OK;
}
/*
** MBDB_LDAP_LOOKUP -- look up a local mail recipient, given name
**
** Parameters:
** name -- name of local mail recipient
** user -- pointer to structure to fill in on success
**
** Results:
** On success, fill in *user and return EX_OK.
** Failure: EX_NOUSER.
*/
static int
char *name;
{
int msgid;
int need;
int ret;
int save_errno;
{
return EX_NOUSER;
}
{
/* map not initialized, but don't have arg here */
return EX_TEMPFAIL;
}
{
/* re-open map in this child process */
}
{
/* map not open, try to open now */
return EX_TEMPFAIL;
}
if (msgid == -1)
{
# ifdef LDAP_SERVER_DOWN
if (errno == LDAP_SERVER_DOWN)
{
/* server disappeared, try reopen on next search */
}
# endif /* LDAP_SERVER_DOWN */
errno = save_errno;
return EX_TEMPFAIL;
}
/* Get results */
&(LDAPLMAP.ldap_timeout)),
if (ret != LDAP_RES_SEARCH_RESULT &&
{
if (ret == 0)
else
ret = EX_TEMPFAIL;
goto abort;
}
{
int rc;
/*
** We may have gotten an LDAP_RES_SEARCH_RESULT response
** with an error inside it, so we have to extract that
** with ldap_parse_result(). This can happen when talking
** to an LDAP proxy whose backend has gone down.
*/
if (save_errno == LDAP_SUCCESS)
save_errno = rc;
if (save_errno == LDAP_SUCCESS)
{
}
else
{
errno = save_errno;
ret = EX_TEMPFAIL;
}
goto abort;
}
# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
/*
** Reset value to prevent lingering
** LDAP_DECODING_ERROR due to
** OpenLDAP 1.X's hack (see below)
*/
# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
{
char **vals;
{
if (errno == LDAP_SUCCESS)
{
continue;
}
/* Must be an error */
errno += E_LDAPBASE;
ret = EX_TEMPFAIL;
goto abort;
}
# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
/*
** Reset value to prevent lingering
** LDAP_DECODING_ERROR due to
** OpenLDAP 1.X's hack (see below)
*/
# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
goto skip;
{
goto skip;
sizeof(user->mbdb_fullname));
need &= ~NEED_FULLNAME;
}
{
goto skip;
sizeof(user->mbdb_homedir));
need &= ~NEED_HOMEDIR;
}
{
goto skip;
sizeof(user->mbdb_shell));
need &= ~NEED_SHELL;
}
{
char *p;
goto skip;
for (p = vals[0]; *p != '\0'; p++)
{
/* allow negative numbers */
if (p == vals[0] && *p == '-')
{
/* but not simply '-' */
if (*(p + 1) == '\0')
goto skip;
}
goto skip;
}
}
{
char *p;
goto skip;
for (p = vals[0]; *p != '\0'; p++)
{
/* allow negative numbers */
if (p == vals[0] && *p == '-')
{
/* but not simply '-' */
if (*(p + 1) == '\0')
goto skip;
}
goto skip;
}
}
skip:
}
/*
** We check errno != LDAP_DECODING_ERROR since
** OpenLDAP 1.X has a very ugly *undocumented*
** hack of returning this error code from
** ldap_next_attribute() if the library freed the
** ber attribute. See:
*/
if (errno != LDAP_SUCCESS &&
{
/* Must be an error */
errno += E_LDAPBASE;
ret = EX_TEMPFAIL;
goto abort;
}
save_errno = errno;
{
}
{
}
{
if (need == 0)
{
save_errno = 0;
}
else
{
save_errno = EINVAL;
}
}
errno = save_errno;
return ret;
}
/*
** MBDB_LDAP_TERMINATE -- terminate connection to the mailbox database
**
** Parameters:
** none.
**
** Results:
** none.
*/
static void
{
}
# endif /* _LDAP_EXAMPLE_ */
#endif /* LDAPMAP */