* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)udb.c 5.5 (Berkeley) %G% (with USERDB)";
static char sccsid
[] = "@(#)udb.c 5.5 (Berkeley) %G% (without USERDB)";
** UDBEXPAND.C -- interface between sendmail and Berkeley User Data Base.
** This depends on the 4.4BSD db package.
char *udb_spec
; /* string version of spec */
int udb_type
; /* type of entry */
/* type UE_REMOTE -- do remote call for lookup */
struct sockaddr_in _udb_addr
; /* address */
int _udb_timeout
; /* timeout */
#define udb_addr udb_u.udb_remote._udb_addr
#define udb_timeout udb_u.udb_remote._udb_timeout
/* type UE_FORWARD -- forward message to remote */
char *_udb_fwdhost
; /* name of forward host */
#define udb_fwdhost udb_u.udb_forward._udb_fwdhost
/* type UE_LOOKUP -- lookup in local database */
char *_udb_dbname
; /* pathname of database */
DB
*_udb_dbp
; /* open database ptr */
#define udb_dbname udb_u.udb_lookup._udb_dbname
#define udb_dbp udb_u.udb_lookup._udb_dbp
#define UDB_EOLIST 0 /* end of list */
#define UDB_SKIP 1 /* skip this entry */
#define UDB_REMOTE 2 /* look up in remote database */
#define UDB_LOOKUP 3 /* look up in local database */
#define UDB_FORWARD 4 /* forward to remote host */
#define MAXUDBENT 10 /* maximum number of UDB entries */
** UDBEXPAND -- look up user in database and expand
** a -- address to expand.
** sendq -- pointer to head of sendq to put the expansions in.
struct udbent UdbEnts
[MAXUDBENT
+ 1];
static bool firstcall
= TRUE
;
register struct udbent
*up
;
printf("expand(%s)\n", a
->q_paddr
);
/* make certain we are supposed to send to this address */
if (bitset(QDONTSEND
, a
->q_flags
) ||
UdbSpec
== NULL
|| UdbSpec
[0] == '\0')
CurEnv
->e_to
= a
->q_paddr
;
/* on first call, locate the database */
extern void _udbx_init();
/* if name is too long, assume it won't match */
if (strlen(a
->q_user
) > sizeof keybuf
- 12)
/* if name begins with a colon, it indicates our metadata */
/* build actual database key */
(void) strcpy(keybuf
, a
->q_user
);
(void) strcat(keybuf
, ":maildrop");
for (up
= UdbEnts
; !breakout
; up
++)
** Select action based on entry type.
** On dropping out of this switch, "class" should
** explain the type of the data, and "user" should
** contain the user information.
i
= (*up
->udb_dbp
->seq
)(up
->udb_dbp
, &key
, &info
, R_CURSOR
);
if (i
!= 0 || info
.size
<= 0)
syserr("udbexpand: db-get stat %s");
printf("expand: no match on %s\n", keybuf
);
/* there is at least one match -- start processing */
if (info
.size
< sizeof buf
)
user
= xalloc(info
.size
+ 1);
bcopy(info
.data
, user
, info
.size
);
message(Arpa_Info
, "expanded to %s", user
);
sendtolist(user
, a
, sendq
);
/* get the next record */
i
= (*up
->udb_dbp
->seq
)(up
->udb_dbp
, &key
, &info
, R_NEXT
);
} while (i
== 0 && key
.size
== keylen
&&
bcmp(key
.data
, keybuf
, keylen
) == 0);
if (sendto(UdbSock
, keybuf
, keylen
, 0,
(struct sockaddr
*) &up
->udb_addr
,
sizeof up
->udb_addr
) < 0)
timeout
.tv_sec
= up
->udb_timeout
/ 10;
timeout
.tv_usec
= (up
->udb_timeout
% 10) * 100000;
i
= select(FD_SETSIZE
, &fdset
, NULL
, NULL
, &timeout
);
} while (i
> 0 && !FD_ISSET(UdbSock
, &fdset
));
i
= recvfrom(UdbSock
, buf
, sizeof buf
- 1, 0, NULL
, NULL
);
if (buf
[0] != ' ' && buf
[0] != '-')
while (buf
[0] == ' ' || buf
[0] == '-')
message(Arpa_Info
, "expanded to %s", user
);
sendtolist(user
, a
, sendq
);
/* try for next record */
i
= recvfrom(UdbSock
, buf
, sizeof buf
- 1, 0, NULL
, NULL
);
i
= strlen(up
->udb_fwdhost
) + strlen(a
->q_user
) + 1;
(void) sprintf(user
, "%s@%s", a
->q_user
, up
->udb_fwdhost
);
message(Arpa_Info
, "expanded to %s", user
);
sendtolist(user
, a
, sendq
);
register struct udbent
*up
;
register struct hostent
*h
;
char *mxhosts
[MAXMXHOSTS
+ 1];
struct option opts
[MAXUDBOPTS
+ 1];
while (*p
== ' ' || *p
== '\t' || *p
== ',')
nopts
= _udb_parsespec(spec
, opts
, MAXUDBOPTS
);
** Decode database specification.
** In the sendmail tradition, the leading character
** defines the semantics of the rest of the entry.
** +hostname -- send a datagram to the udb server
** on host "hostname" asking for the
** home mail server for this user.
** *hostname -- similar to +hostname, except that the
** hostname is searched as an MX record;
** resulting hosts are searched as for
** +mxhostname. If no MX host is found,
** this is the same as +hostname.
** @hostname -- forward email to the indicated host.
** This should be the last in the list,
** since it always matches the input.
** /dbname -- search the named database on the local
** host using the Berkeley db package.
case '+': /* search remote database */
case '*': /* search remote database (expand MX) */
nmx
= getmxrr(spec
+ 1, mxhosts
, "", &rcode
);
printf("getmxrr(%s): %d", spec
+ 1, nmx
);
for (i
= 0; i
<= nmx
; i
++)
printf(" %s", mxhosts
[i
]);
for (i
= 0; i
< nmx
; i
++)
h
= gethostbyname(mxhosts
[i
]);
up
->udb_type
= UDB_REMOTE
;
up
->udb_addr
.sin_family
= h
->h_addrtype
;
up
->udb_addr
.sin_len
= h
->h_length
;
(char *) &up
->udb_addr
.sin_addr
,
up
->udb_addr
.sin_port
= UdbPort
;
up
->udb_timeout
= UdbTimeout
;
/* set up a datagram socket */
UdbSock
= socket(AF_INET
, SOCK_DGRAM
, 0);
(void) fcntl(UdbSock
, F_SETFD
, 1);
case '@': /* forward to remote host */
up
->udb_type
= UDB_FORWARD
;
up
->udb_fwdhost
= spec
+ 1;
case '/': /* look up remote name */
up
->udb_dbp
= dbopen(spec
, O_RDONLY
, 0644, DB_BTREE
, NULL
);
up
->udb_type
= UDB_LOOKUP
;
up
->udb_type
= UDB_EOLIST
;
for (up
= UdbEnts
; ; up
++)
printf("REMOTE: addr %s, timeo %d\n",
inet_ntoa(up
->udb_addr
.sin_addr
),
printf("FORWARD: host %s\n",
_udb_parsespec(udbspec
, opt
, maxopts
)
spec_end
= index(udbspec
, ':');
for (optnum
= 0; optnum
< maxopts
&& (spec
= spec_end
) != NULL
; optnum
++)
spec_end
= index(spec
, ':');