diff options
Diffstat (limited to 'contrib/sendmail/libsm/mbdb.c')
-rw-r--r-- | contrib/sendmail/libsm/mbdb.c | 774 |
1 files changed, 0 insertions, 774 deletions
diff --git a/contrib/sendmail/libsm/mbdb.c b/contrib/sendmail/libsm/mbdb.c deleted file mode 100644 index ad0e7ccbd13ff..0000000000000 --- a/contrib/sendmail/libsm/mbdb.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * 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.40 2003/12/10 03:19:07 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_host = MBDB_DEFAULT_LDAP_SERVER; - LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER; - - /* Only want one match */ - LDAPLMAP.ldap_sizelimit = 1; - - /* interpolate new ldap_base and ldap_host 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_host = 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 */ |