diff options
author | Andreas Beckmann <debian@abeckmann.de> | 2012-10-01 19:58:38 +0200 |
---|---|---|
committer | Andreas Beckmann <debian@abeckmann.de> | 2012-10-01 19:58:38 +0200 |
commit | 6b71060b84a2d9111ec847e66cc5160aab8a45e8 (patch) | |
tree | 599eb55ae3e0ec0f95d829c185831f3027eec78b /src/udb.c | |
parent | 6c193ce1dd1d07ebdc1372e38bc4908ab1c37705 (diff) | |
download | sendmail-6b71060b84a2d9111ec847e66cc5160aab8a45e8.tar.gz |
Imported Upstream version 8.9.3upstream/8.9.3
Diffstat (limited to 'src/udb.c')
-rw-r--r-- | src/udb.c | 283 |
1 files changed, 229 insertions, 54 deletions
@@ -1,44 +1,22 @@ /* - * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 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. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ #include "sendmail.h" #ifndef lint #if USERDB -static char sccsid [] = "@(#)udb.c 8.51 (Berkeley) 5/29/97 (with USERDB)"; +static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (with USERDB)"; #else -static char sccsid [] = "@(#)udb.c 8.51 (Berkeley) 5/29/97 (without USERDB)"; +static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (without USERDB)"; #endif #endif @@ -48,6 +26,9 @@ static char sccsid [] = "@(#)udb.c 8.51 (Berkeley) 5/29/97 (without USERDB)"; #ifdef NEWDB # include <db.h> +# ifndef DB_VERSION_MAJOR +# define DB_VERSION_MAJOR 1 +# endif #else # define DBT struct _data_base_thang_ DBT @@ -57,10 +38,6 @@ DBT }; #endif -#ifdef HESIOD -# include <hesiod.h> -#endif /* HESIOD */ - /* ** UDB.C -- interface between sendmail and Berkeley User Data Base. ** @@ -72,6 +49,7 @@ struct udbent { char *udb_spec; /* string version of spec */ int udb_type; /* type of entry */ + pid_t udb_pid; /* PID of process which opened db */ char *udb_default; /* default host for outgoing mail */ union { @@ -114,12 +92,15 @@ struct udbent #define MAXUDBENT 10 /* maximum number of UDB entries */ -struct option +struct udb_option { char *name; char *val; }; +#ifdef HESIOD +extern int hes_udb_get __P((DBT *, DBT *)); +#endif extern int _udbx_init __P((ENVELOPE *)); /* ** UDBEXPAND -- look up user in database and expand @@ -160,8 +141,12 @@ udbexpand(a, sendq, aliaslevel, e) register struct udbent *up; int keylen; int naddrs; + char *user; char keybuf[MAXKEY]; + bzero(&key, sizeof key); + bzero(&info, sizeof info); + if (tTd(28, 1)) printf("udbexpand(%s)\n", a->q_paddr); @@ -181,20 +166,24 @@ udbexpand(a, sendq, aliaslevel, e) if (UdbSpec == NULL || UdbSpec[0] == '\0') return EX_OK; + /* extract user to do userdb matching on */ + user = a->q_user; + /* short circuit name begins with '\\' since it can't possibly match */ - if (a->q_user[0] == '\\') + /* (might want to treat this as unquoted instead) */ + if (user[0] == '\\') return EX_OK; /* if name is too long, assume it won't match */ - if (strlen(a->q_user) > (SIZE_T) sizeof keybuf - 12) + if (strlen(user) > (SIZE_T) sizeof keybuf - 12) return EX_OK; /* if name begins with a colon, it indicates our metadata */ - if (a->q_user[0] == ':') + if (user[0] == ':') return EX_OK; /* build actual database key */ - (void) strcpy(keybuf, a->q_user); + (void) strcpy(keybuf, user); (void) strcat(keybuf, ":maildrop"); keylen = strlen(keybuf); @@ -208,6 +197,9 @@ udbexpand(a, sendq, aliaslevel, e) #if defined(HESIOD) && defined(HES_GETMAILHOST) char pobuf[MAXNAME]; #endif +#if defined(NEWDB) && DB_VERSION_MAJOR > 1 + DBC *dbc = NULL; +#endif user = userbuf; userbuf[0] = '\0'; @@ -231,12 +223,36 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 80)) printf("udbexpand: trying %s (%d) via db\n", keybuf, keylen); +#if DB_VERSION_MAJOR < 2 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); +#else + i = 0; + if (dbc == NULL && +# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6 + (errno = (*up->udb_dbp->cursor)(up->udb_dbp, + NULL, &dbc, 0)) != 0) +# else + (errno = (*up->udb_dbp->cursor)(up->udb_dbp, + NULL, &dbc)) != 0) +# endif + i = -1; + if (i != 0 || dbc == NULL || + (errno = dbc->c_get(dbc, &key, + &info, DB_SET)) != 0) + i = 1; +#endif if (i > 0 || info.size <= 0) { if (tTd(28, 2)) printf("udbexpand: no match on %s (%d)\n", keybuf, keylen); +#if DB_VERSION_MAJOR > 1 + if (dbc != NULL) + { + (void) dbc->c_close(dbc); + dbc = NULL; + } +#endif break; } if (tTd(28, 80)) @@ -253,6 +269,13 @@ udbexpand(a, sendq, aliaslevel, e) if (bitset(EF_VRFYONLY, e->e_flags)) { a->q_flags |= QVERIFIED; +#if DB_VERSION_MAJOR > 1 + if (dbc != NULL) + { + (void) dbc->c_close(dbc); + dbc = NULL; + } +#endif return EX_OK; } @@ -284,9 +307,24 @@ udbexpand(a, sendq, aliaslevel, e) userleft -= info.size; /* get the next record */ +#if DB_VERSION_MAJOR < 2 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); +#else + i = 0; + if ((errno = dbc->c_get(dbc, &key, + &info, DB_NEXT)) != 0) + i = 1; +#endif } +#if DB_VERSION_MAJOR > 1 + if (dbc != NULL) + { + (void) dbc->c_close(dbc); + dbc = NULL; + } +#endif + /* if nothing ever matched, try next database */ if (!breakout) break; @@ -296,7 +334,7 @@ udbexpand(a, sendq, aliaslevel, e) sm_syslog(LOG_INFO, e->e_id, "expand %.100s => %s", e->e_to, - shortenstring(user, 203)); + shortenstring(user, MAXSHORTSTR)); naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { @@ -310,7 +348,7 @@ udbexpand(a, sendq, aliaslevel, e) if (i < 0) { syserr("udbexpand: db-get %.*s stat %d", - key.size, key.data, i); + (int) key.size, (char *) key.data, i); return EX_TEMPFAIL; } @@ -319,12 +357,20 @@ udbexpand(a, sendq, aliaslevel, e) ** it into the envelope. */ + bzero(&key, sizeof key); + bzero(&info, sizeof info); (void) strcpy(keybuf, a->q_user); (void) strcat(keybuf, ":mailsender"); keylen = strlen(keybuf); key.data = keybuf; key.size = keylen; + +#if DB_VERSION_MAJOR < 2 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); +#else + i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, + &key, &info, 0); +#endif if (i != 0 || info.size <= 0) break; a->q_owner = xalloc(info.size + 1); @@ -355,7 +401,7 @@ udbexpand(a, sendq, aliaslevel, e) if (i < 0) { syserr("udbexpand: hesiod-get %.*s stat %d", - key.size, key.data, i); + (int) key.size, (char *) key.data, i); return EX_TEMPFAIL; } else if (i > 0 || info.size <= 0) @@ -366,7 +412,7 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 2)) printf("udbexpand: no match on %s (%d)\n", - keybuf, keylen); + (char *) keybuf, (int) keylen); #if HES_GETMAILHOST if (tTd(28, 8)) printf(" ... trying hes_getmailhost(%s)\n", @@ -405,7 +451,8 @@ udbexpand(a, sendq, aliaslevel, e) } if (tTd(28, 80)) printf("udbexpand: match %.*s: %.*s\n", - key.size, key.data, info.size, info.data); + (int) key.size, (char *) key.data, + (int) info.size, (char *) info.data); a->q_flags &= ~QSELFREF; if (bitset(EF_VRFYONLY, e->e_flags)) @@ -425,7 +472,7 @@ udbexpand(a, sendq, aliaslevel, e) sm_syslog(LOG_INFO, e->e_id, "hesiod %.100s => %s", e->e_to, - shortenstring(user, 203)); + shortenstring(user, MAXSHORTSTR)); naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) @@ -519,7 +566,7 @@ char * udbsender(sender) char *sender; { - extern char *udbmatch(); + extern char *udbmatch __P((char *, char *)); return udbmatch(sender, "mailname"); } @@ -581,9 +628,16 @@ udbmatch(user, field) { #ifdef NEWDB case UDB_DBFETCH: + bzero(&key, sizeof key); + bzero(&info, sizeof info); key.data = keybuf; key.size = keylen; +#if DB_VERSION_MAJOR < 2 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); +#else + i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, + &key, &info, 0); +#endif if (i != 0 || info.size <= 0) { if (tTd(28, 2)) @@ -598,7 +652,6 @@ udbmatch(user, field) if (tTd(28, 1)) printf("udbmatch ==> %s\n", p); return p; - break; #endif #ifdef HESIOD @@ -647,9 +700,18 @@ udbmatch(user, field) /* get the default case for this database */ if (up->udb_default == NULL) { + bzero(&key, sizeof key); + bzero(&info, sizeof info); key.data = ":default:mailname"; key.size = strlen(key.data); - i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); +#if DB_VERSION_MAJOR < 2 + i = (*up->udb_dbp->get)(up->udb_dbp, + &key, &info, 0); +#else + i = errno = (*up->udb_dbp->get)(up->udb_dbp, + NULL, &key, + &info, 0); +#endif if (i != 0 || info.size <= 0) { /* no default case */ @@ -666,9 +728,16 @@ udbmatch(user, field) continue; /* we have a default case -- verify user:maildrop */ + bzero(&key, sizeof key); + bzero(&info, sizeof info); key.data = keybuf; key.size = keylen; +#if DB_VERSION_MAJOR < 2 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); +#else + i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL, + &key, &info, 0); +#endif if (i != 0 || info.size <= 0) { /* nope -- no aliasing for this user */ @@ -683,7 +752,6 @@ udbmatch(user, field) if (tTd(28, 1)) printf("udbmatch ==> %s\n", p); return p; - break; #endif #ifdef HESIOD @@ -750,6 +818,7 @@ udbmatch(user, field) ** The rewritten name otherwise. */ +/* ARGSUSED3 */ char * udb_map_lookup(map, name, av, statp) MAP *map; @@ -809,6 +878,7 @@ int _udbx_init(e) ENVELOPE *e; { + int ents = 0; register char *p; register struct udbent *up; @@ -825,7 +895,6 @@ _udbx_init(e) while (p != NULL) { char *spec; - int nopts; int l; # if 0 auto int rcode; @@ -834,8 +903,8 @@ _udbx_init(e) register struct hostent *h; char *mxhosts[MAXMXHOSTS + 1]; # endif - struct option opts[MAXUDBOPTS + 1]; - extern int _udb_parsespec __P((char *, struct option [], int)); + struct udb_option opts[MAXUDBOPTS + 1]; + extern int _udb_parsespec __P((char *, struct udb_option [], int)); while (*p == ' ' || *p == '\t' || *p == ',') p++; @@ -846,8 +915,14 @@ _udbx_init(e) if (p != NULL) *p++ = '\0'; + if (ents >= MAXUDBENT) + { + syserr("Maximum number of UDB entries exceeded"); + break; + } + /* extract options */ - nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); + (void) _udb_parsespec(spec, opts, MAXUDBOPTS); /* ** Decode database specification. @@ -908,12 +983,14 @@ _udbx_init(e) if (h == NULL) continue; up->udb_type = UDB_REMOTE; + up->udb_pid = getpid(); up->udb_addr.sin_family = h->h_addrtype; bcopy(h->h_addr_list[0], (char *) &up->udb_addr.sin_addr, INADDRSZ); up->udb_addr.sin_port = UdbPort; up->udb_timeout = UdbTimeout; + ents++; up++; } @@ -928,7 +1005,9 @@ _udbx_init(e) case '@': /* forward to remote host */ up->udb_type = UDB_FORWARD; + up->udb_pid = getpid(); up->udb_fwdhost = spec + 1; + ents++; up++; break; @@ -938,6 +1017,8 @@ _udbx_init(e) if (strcasecmp(spec, "hesiod") != 0) goto badspec; up->udb_type = UDB_HESIOD; + up->udb_pid = getpid(); + ents++; up++; break; #endif /* HESIOD */ @@ -956,15 +1037,25 @@ _udbx_init(e) strcat(up->udb_dbname, ".db"); } errno = 0; +#if DB_VERSION_MAJOR < 2 up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY, 0644, DB_BTREE, NULL); +#else + up->udb_dbp = NULL; + errno = db_open(up->udb_dbname, DB_BTREE, DB_RDONLY, + 0644, NULL, NULL, &up->udb_dbp); +#endif if (up->udb_dbp == NULL) { if (tTd(28, 1)) { int saveerrno = errno; +#if DB_VERSION_MAJOR < 2 printf("dbopen(%s): %s\n", +#else + printf("db_open(%s): %s\n", +#endif up->udb_dbname, errstring(errno)); errno = saveerrno; @@ -973,7 +1064,11 @@ _udbx_init(e) { if (LogLevel > 2) sm_syslog(LOG_ERR, e->e_id, +#if DB_VERSION_MAJOR < 2 "dbopen(%s): %s", +#else + "db_open(%s): %s", +#endif up->udb_dbname, errstring(errno)); up->udb_type = UDB_EOLIST; @@ -985,7 +1080,18 @@ _udbx_init(e) free(up->udb_dbname); break; } + if (tTd(28, 1)) + { +#if DB_VERSION_MAJOR < 2 + printf("_udbx_init: dbopen(%s)\n", +#else + printf("_udbx_init: db_open(%s)\n", +#endif + up->udb_dbname); + } up->udb_type = UDB_DBFETCH; + up->udb_pid = getpid(); + ents++; up++; break; #endif @@ -1051,7 +1157,16 @@ badspec: { if (up->udb_type == UDB_DBFETCH) { +#if DB_VERSION_MAJOR < 2 (*up->udb_dbp->close)(up->udb_dbp); +#else + errno = (*up->udb_dbp->close)(up->udb_dbp, 0); +#endif + if (tTd(28, 1)) + { + printf("_udbx_init: db->close(%s)\n", + up->udb_dbname); + } } } #endif @@ -1061,7 +1176,7 @@ badspec: int _udb_parsespec(udbspec, opt, maxopts) char *udbspec; - struct option opt[]; + struct udb_option opt[]; int maxopts; { register char *spec; @@ -1087,6 +1202,48 @@ _udb_parsespec(udbspec, opt, maxopts) } return optnum; } +/* +** _UDBX_CLOSE -- close all file based UDB entries. +** +** Parameters: +** none +** +** Returns: +** none +*/ +void +_udbx_close() +{ + pid_t pid; + struct udbent *up; + + if (!UdbInitialized) + return; + + pid = getpid(); + + for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) + { + if (up->udb_pid != pid) + continue; + +#ifdef NEWDB + if (up->udb_type == UDB_DBFETCH) + { +#if DB_VERSION_MAJOR < 2 + (*up->udb_dbp->close)(up->udb_dbp); +#else + errno = (*up->udb_dbp->close)(up->udb_dbp, 0); +#endif + } + if (tTd(28, 1)) + { + printf("_udbx_init: db->close(%s)\n", + up->udb_dbname); + } +#endif + } +} #ifdef HESIOD @@ -1096,7 +1253,7 @@ hes_udb_get(key, info) DBT *info; { char *name, *type; - char *p, **hp; + char **hp; char kbuf[MAXKEY + 1]; if (strlen(key->data) >= (SIZE_T) sizeof kbuf) @@ -1114,8 +1271,25 @@ hes_udb_get(key, info) printf("hes_udb_get(%s, %s)\n", name, type); /* make the hesiod query */ +#ifdef HESIOD_INIT + if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0) + return -1; + hp = hesiod_resolve(HesiodContext, name, type); +#else hp = hes_resolve(name, type); +#endif /* HESIOD_INIT */ *--type = ':'; +#ifdef HESIOD_INIT + if (hp == NULL) + return 1; + if (*hp == NULL) + { + hesiod_free_list(HesiodContext, hp); + if (errno == ECONNREFUSED || errno == EMSGSIZE) + return -1; + return 1; + } +#else if (hp == NULL || hp[0] == NULL) { /* network problem or timeout */ @@ -1124,6 +1298,7 @@ hes_udb_get(key, info) return 1; } +#endif /* HESIOD_INIT */ else { /* |