775 lines
16 KiB
C
775 lines
16 KiB
C
/*
|
|
* Copyright (c) 2001-2002 Sendmail, 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 <sm/gen.h>
|
|
SM_RCSID("@(#)$Id: mbdb.c,v 1.38.2.1 2002/11/20 22:59:06 gshapiro Exp $")
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <pwd.h>
|
|
#include <stdlib.h>
|
|
#include <setjmp.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sm/limits.h>
|
|
#include <sm/conf.h>
|
|
#include <sm/assert.h>
|
|
#include <sm/bitops.h>
|
|
#include <sm/errstring.h>
|
|
#include <sm/heap.h>
|
|
#include <sm/mbdb.h>
|
|
#include <sm/string.h>
|
|
# ifdef EX_OK
|
|
# undef EX_OK /* for SVr4.2 SMP */
|
|
# endif /* EX_OK */
|
|
#include <sm/sysexits.h>
|
|
|
|
#if LDAPMAP
|
|
# if _LDAP_EXAMPLE_
|
|
# include <sm/ldap.h>
|
|
# endif /* _LDAP_EXAMPLE_ */
|
|
#endif /* LDAPMAP */
|
|
|
|
typedef struct
|
|
{
|
|
char *mbdb_typename;
|
|
int (*mbdb_initialize) __P((char *));
|
|
int (*mbdb_lookup) __P((char *name, SM_MBDB_T *user));
|
|
void (*mbdb_terminate) __P((void));
|
|
} SM_MBDB_TYPE_T;
|
|
|
|
static int mbdb_pw_initialize __P((char *));
|
|
static int mbdb_pw_lookup __P((char *name, SM_MBDB_T *user));
|
|
static void mbdb_pw_terminate __P((void));
|
|
|
|
#if LDAPMAP
|
|
# if _LDAP_EXAMPLE_
|
|
static struct sm_ldap_struct LDAPLMAP;
|
|
static int mbdb_ldap_initialize __P((char *));
|
|
static int mbdb_ldap_lookup __P((char *name, SM_MBDB_T *user));
|
|
static void mbdb_ldap_terminate __P((void));
|
|
# endif /* _LDAP_EXAMPLE_ */
|
|
#endif /* LDAPMAP */
|
|
|
|
static SM_MBDB_TYPE_T SmMbdbTypes[] =
|
|
{
|
|
{ "pw", mbdb_pw_initialize, mbdb_pw_lookup, mbdb_pw_terminate },
|
|
#if LDAPMAP
|
|
# if _LDAP_EXAMPLE_
|
|
{ "ldap", mbdb_ldap_initialize, mbdb_ldap_lookup, mbdb_ldap_terminate },
|
|
# endif /* _LDAP_EXAMPLE_ */
|
|
#endif /* LDAPMAP */
|
|
{ NULL, NULL, NULL, NULL }
|
|
};
|
|
|
|
static SM_MBDB_TYPE_T *SmMbdbType = &SmMbdbTypes[0];
|
|
|
|
/*
|
|
** 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
|
|
sm_mbdb_initialize(mbdb)
|
|
char *mbdb;
|
|
{
|
|
size_t namelen;
|
|
int err;
|
|
char *name;
|
|
char *arg;
|
|
SM_MBDB_TYPE_T *t;
|
|
|
|
SM_REQUIRE(mbdb != NULL);
|
|
|
|
name = mbdb;
|
|
arg = strchr(mbdb, '.');
|
|
if (arg == NULL)
|
|
namelen = strlen(name);
|
|
else
|
|
{
|
|
namelen = arg - name;
|
|
++arg;
|
|
}
|
|
|
|
for (t = SmMbdbTypes; t->mbdb_typename != NULL; ++t)
|
|
{
|
|
if (strlen(t->mbdb_typename) == namelen &&
|
|
strncmp(name, t->mbdb_typename, namelen) == 0)
|
|
{
|
|
err = EX_OK;
|
|
if (t->mbdb_initialize != NULL)
|
|
err = t->mbdb_initialize(arg);
|
|
if (err == EX_OK)
|
|
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_terminate()
|
|
{
|
|
if (SmMbdbType->mbdb_terminate != NULL)
|
|
SmMbdbType->mbdb_terminate();
|
|
}
|
|
|
|
/*
|
|
** 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
|
|
sm_mbdb_lookup(name, user)
|
|
char *name;
|
|
SM_MBDB_T *user;
|
|
{
|
|
int ret = EX_NOUSER;
|
|
|
|
if (SmMbdbType->mbdb_lookup != NULL)
|
|
ret = SmMbdbType->mbdb_lookup(name, user);
|
|
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
|
|
sm_mbdb_frompw(user, pw)
|
|
SM_MBDB_T *user;
|
|
struct passwd *pw;
|
|
{
|
|
SM_REQUIRE(user != NULL);
|
|
(void) sm_strlcpy(user->mbdb_name, pw->pw_name,
|
|
sizeof(user->mbdb_name));
|
|
user->mbdb_uid = pw->pw_uid;
|
|
user->mbdb_gid = pw->pw_gid;
|
|
sm_pwfullname(pw->pw_gecos, pw->pw_name, user->mbdb_fullname,
|
|
sizeof(user->mbdb_fullname));
|
|
(void) sm_strlcpy(user->mbdb_homedir, pw->pw_dir,
|
|
sizeof(user->mbdb_homedir));
|
|
(void) sm_strlcpy(user->mbdb_shell, pw->pw_shell,
|
|
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.
|
|
*/
|
|
|
|
#if _FFR_HANDLE_ISO8859_GECOS
|
|
static char Latin1ToASCII[128] =
|
|
{
|
|
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
|
|
sm_pwfullname(gecos, user, buf, buflen)
|
|
register char *gecos;
|
|
char *user;
|
|
char *buf;
|
|
size_t buflen;
|
|
{
|
|
register char *p;
|
|
register char *bp = buf;
|
|
|
|
if (*gecos == '*')
|
|
gecos++;
|
|
|
|
/* copy gecos, interpolating & to be full name */
|
|
for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
|
|
{
|
|
if (bp >= &buf[buflen - 1])
|
|
{
|
|
/* buffer overflow -- just use login name */
|
|
(void) sm_strlcpy(buf, user, buflen);
|
|
return;
|
|
}
|
|
if (*p == '&')
|
|
{
|
|
/* interpolate full name */
|
|
(void) sm_strlcpy(bp, user, buflen - (bp - buf));
|
|
*bp = toupper(*bp);
|
|
bp += strlen(bp);
|
|
}
|
|
else
|
|
{
|
|
#if _FFR_HANDLE_ISO8859_GECOS
|
|
if ((unsigned char) *p >= 128)
|
|
*bp++ = Latin1ToASCII[(unsigned char) *p - 128];
|
|
else
|
|
#endif /* _FFR_HANDLE_ISO8859_GECOS */
|
|
*bp++ = *p;
|
|
}
|
|
}
|
|
*bp = '\0';
|
|
}
|
|
|
|
/*
|
|
** /etc/passwd implementation.
|
|
*/
|
|
|
|
/*
|
|
** MBDB_PW_INITIALIZE -- initialize getpwnam() version
|
|
**
|
|
** Parameters:
|
|
** arg -- unused.
|
|
**
|
|
** Results:
|
|
** EX_OK.
|
|
*/
|
|
|
|
/* ARGSUSED0 */
|
|
static int
|
|
mbdb_pw_initialize(arg)
|
|
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
|
|
mbdb_pw_lookup(name, user)
|
|
char *name;
|
|
SM_MBDB_T *user;
|
|
{
|
|
struct passwd *pw;
|
|
|
|
#ifdef HESIOD
|
|
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
|
|
{
|
|
char *p;
|
|
|
|
for (p = name; *p != '\0'; p++)
|
|
if (!isascii(*p) || !isdigit(*p))
|
|
break;
|
|
if (*p == '\0')
|
|
return EX_NOUSER;
|
|
}
|
|
#endif /* HESIOD */
|
|
|
|
errno = 0;
|
|
pw = getpwnam(name);
|
|
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;
|
|
}
|
|
|
|
/*
|
|
** MBDB_PW_TERMINATE -- terminate connection to the mailbox database
|
|
**
|
|
** Parameters:
|
|
** none.
|
|
**
|
|
** Results:
|
|
** none.
|
|
*/
|
|
|
|
static void
|
|
mbdb_pw_terminate()
|
|
{
|
|
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 ) )
|
|
**
|
|
*/
|
|
|
|
# define MBDB_LDAP_LABEL "MailboxDatabase"
|
|
|
|
# ifndef MBDB_LDAP_FILTER
|
|
# define MBDB_LDAP_FILTER "(&(objectClass=posixAccount)(uid=%0))"
|
|
# endif /* MBDB_LDAP_FILTER */
|
|
|
|
# ifndef MBDB_DEFAULT_LDAP_BASEDN
|
|
# define MBDB_DEFAULT_LDAP_BASEDN NULL
|
|
# endif /* MBDB_DEFAULT_LDAP_BASEDN */
|
|
|
|
# ifndef MBDB_DEFAULT_LDAP_SERVER
|
|
# define MBDB_DEFAULT_LDAP_SERVER NULL
|
|
# 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
|
|
mbdb_ldap_initialize(arg)
|
|
char *arg;
|
|
{
|
|
sm_ldap_clear(&LDAPLMAP);
|
|
LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN;
|
|
LDAPLMAP.ldap_target = MBDB_DEFAULT_LDAP_SERVER;
|
|
LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER;
|
|
|
|
/* Only want one match */
|
|
LDAPLMAP.ldap_sizelimit = 1;
|
|
|
|
/* interpolate new ldap_base and ldap_target from arg if given */
|
|
if (arg != NULL && *arg != '\0')
|
|
{
|
|
char *new;
|
|
char *sep;
|
|
size_t len;
|
|
|
|
len = strlen(arg) + 1;
|
|
new = sm_malloc(len);
|
|
if (new == NULL)
|
|
return EX_TEMPFAIL;
|
|
(void) sm_strlcpy(new, arg, len);
|
|
sep = strrchr(new, '@');
|
|
if (sep != NULL)
|
|
{
|
|
*sep++ = '\0';
|
|
LDAPLMAP.ldap_target = sep;
|
|
}
|
|
LDAPLMAP.ldap_base = new;
|
|
}
|
|
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.
|
|
*/
|
|
|
|
#define NEED_FULLNAME 0x01
|
|
#define NEED_HOMEDIR 0x02
|
|
#define NEED_SHELL 0x04
|
|
#define NEED_UID 0x08
|
|
#define NEED_GID 0x10
|
|
|
|
static int
|
|
mbdb_ldap_lookup(name, user)
|
|
char *name;
|
|
SM_MBDB_T *user;
|
|
{
|
|
int msgid;
|
|
int need;
|
|
int ret;
|
|
int save_errno;
|
|
LDAPMessage *entry;
|
|
BerElement *ber;
|
|
char *attr = NULL;
|
|
|
|
if (strlen(name) >= sizeof(user->mbdb_name))
|
|
{
|
|
errno = EINVAL;
|
|
return EX_NOUSER;
|
|
}
|
|
|
|
if (LDAPLMAP.ldap_filter == NULL)
|
|
{
|
|
/* map not initialized, but don't have arg here */
|
|
errno = EFAULT;
|
|
return EX_TEMPFAIL;
|
|
}
|
|
|
|
if (LDAPLMAP.ldap_pid != getpid())
|
|
{
|
|
/* re-open map in this child process */
|
|
LDAPLMAP.ldap_ld = NULL;
|
|
}
|
|
|
|
if (LDAPLMAP.ldap_ld == NULL)
|
|
{
|
|
/* map not open, try to open now */
|
|
if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP))
|
|
return EX_TEMPFAIL;
|
|
}
|
|
|
|
sm_ldap_setopts(LDAPLMAP.ldap_ld, &LDAPLMAP);
|
|
msgid = sm_ldap_search(&LDAPLMAP, name);
|
|
if (msgid == -1)
|
|
{
|
|
save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld) + E_LDAPBASE;
|
|
# ifdef LDAP_SERVER_DOWN
|
|
if (errno == LDAP_SERVER_DOWN)
|
|
{
|
|
/* server disappeared, try reopen on next search */
|
|
sm_ldap_close(&LDAPLMAP);
|
|
}
|
|
# endif /* LDAP_SERVER_DOWN */
|
|
errno = save_errno;
|
|
return EX_TEMPFAIL;
|
|
}
|
|
|
|
/* Get results */
|
|
ret = ldap_result(LDAPLMAP.ldap_ld, msgid, 1,
|
|
(LDAPLMAP.ldap_timeout.tv_sec == 0 ? NULL :
|
|
&(LDAPLMAP.ldap_timeout)),
|
|
&(LDAPLMAP.ldap_res));
|
|
|
|
if (ret != LDAP_RES_SEARCH_RESULT &&
|
|
ret != LDAP_RES_SEARCH_ENTRY)
|
|
{
|
|
if (ret == 0)
|
|
errno = ETIMEDOUT;
|
|
else
|
|
errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
|
|
ret = EX_TEMPFAIL;
|
|
goto abort;
|
|
}
|
|
|
|
entry = ldap_first_entry(LDAPLMAP.ldap_ld, LDAPLMAP.ldap_res);
|
|
if (entry == NULL)
|
|
{
|
|
save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
|
|
if (save_errno == LDAP_SUCCESS)
|
|
{
|
|
errno = ENOENT;
|
|
ret = EX_NOUSER;
|
|
}
|
|
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)
|
|
*/
|
|
|
|
LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
|
|
# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
|
|
|
|
ret = EX_OK;
|
|
need = NEED_FULLNAME|NEED_HOMEDIR|NEED_SHELL|NEED_UID|NEED_GID;
|
|
for (attr = ldap_first_attribute(LDAPLMAP.ldap_ld, entry, &ber);
|
|
attr != NULL;
|
|
attr = ldap_next_attribute(LDAPLMAP.ldap_ld, entry, ber))
|
|
{
|
|
char **vals;
|
|
|
|
vals = ldap_get_values(LDAPLMAP.ldap_ld, entry, attr);
|
|
if (vals == NULL)
|
|
{
|
|
errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
|
|
if (errno == LDAP_SUCCESS)
|
|
{
|
|
ldap_memfree(attr);
|
|
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)
|
|
*/
|
|
|
|
LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
|
|
# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
|
|
|
|
if (vals[0] == NULL || vals[0][0] == '\0')
|
|
goto skip;
|
|
|
|
if (strcasecmp(attr, "gecos") == 0)
|
|
{
|
|
if (!bitset(NEED_FULLNAME, need) ||
|
|
strlen(vals[0]) >= sizeof(user->mbdb_fullname))
|
|
goto skip;
|
|
|
|
sm_pwfullname(vals[0], name, user->mbdb_fullname,
|
|
sizeof(user->mbdb_fullname));
|
|
need &= ~NEED_FULLNAME;
|
|
}
|
|
else if (strcasecmp(attr, "homeDirectory") == 0)
|
|
{
|
|
if (!bitset(NEED_HOMEDIR, need) ||
|
|
strlen(vals[0]) >= sizeof(user->mbdb_homedir))
|
|
goto skip;
|
|
|
|
(void) sm_strlcpy(user->mbdb_homedir, vals[0],
|
|
sizeof(user->mbdb_homedir));
|
|
need &= ~NEED_HOMEDIR;
|
|
}
|
|
else if (strcasecmp(attr, "loginShell") == 0)
|
|
{
|
|
if (!bitset(NEED_SHELL, need) ||
|
|
strlen(vals[0]) >= sizeof(user->mbdb_shell))
|
|
goto skip;
|
|
|
|
(void) sm_strlcpy(user->mbdb_shell, vals[0],
|
|
sizeof(user->mbdb_shell));
|
|
need &= ~NEED_SHELL;
|
|
}
|
|
else if (strcasecmp(attr, "uidNumber") == 0)
|
|
{
|
|
char *p;
|
|
|
|
if (!bitset(NEED_UID, need))
|
|
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;
|
|
}
|
|
else if (!isascii(*p) || !isdigit(*p))
|
|
goto skip;
|
|
}
|
|
user->mbdb_uid = atoi(vals[0]);
|
|
need &= ~NEED_UID;
|
|
}
|
|
else if (strcasecmp(attr, "gidNumber") == 0)
|
|
{
|
|
char *p;
|
|
|
|
if (!bitset(NEED_GID, need))
|
|
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;
|
|
}
|
|
else if (!isascii(*p) || !isdigit(*p))
|
|
goto skip;
|
|
}
|
|
user->mbdb_gid = atoi(vals[0]);
|
|
need &= ~NEED_GID;
|
|
}
|
|
|
|
skip:
|
|
ldap_value_free(vals);
|
|
ldap_memfree(attr);
|
|
}
|
|
|
|
errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
|
|
|
|
/*
|
|
** 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:
|
|
** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
|
|
*/
|
|
|
|
if (errno != LDAP_SUCCESS &&
|
|
errno != LDAP_DECODING_ERROR)
|
|
{
|
|
/* Must be an error */
|
|
errno += E_LDAPBASE;
|
|
ret = EX_TEMPFAIL;
|
|
goto abort;
|
|
}
|
|
|
|
abort:
|
|
save_errno = errno;
|
|
if (attr != NULL)
|
|
{
|
|
ldap_memfree(attr);
|
|
attr = NULL;
|
|
}
|
|
if (LDAPLMAP.ldap_res != NULL)
|
|
{
|
|
ldap_msgfree(LDAPLMAP.ldap_res);
|
|
LDAPLMAP.ldap_res = NULL;
|
|
}
|
|
if (ret == EX_OK)
|
|
{
|
|
if (need == 0)
|
|
{
|
|
(void) sm_strlcpy(user->mbdb_name, name,
|
|
sizeof(user->mbdb_name));
|
|
save_errno = 0;
|
|
}
|
|
else
|
|
{
|
|
ret = EX_NOUSER;
|
|
save_errno = EINVAL;
|
|
}
|
|
}
|
|
errno = save_errno;
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
** MBDB_LDAP_TERMINATE -- terminate connection to the mailbox database
|
|
**
|
|
** Parameters:
|
|
** none.
|
|
**
|
|
** Results:
|
|
** none.
|
|
*/
|
|
|
|
static void
|
|
mbdb_ldap_terminate()
|
|
{
|
|
sm_ldap_close(&LDAPLMAP);
|
|
}
|
|
# endif /* _LDAP_EXAMPLE_ */
|
|
#endif /* LDAPMAP */
|