Still cleaning up from gnu reorganiztion.
[unix-history] / usr.sbin / sendmail / src / udb.c
CommitLineData
6f14531a
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include "sendmail.h"
36
37#ifndef lint
38#ifdef USERDB
d747e748 39static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 8/25/93 (with USERDB)";
6f14531a 40#else
d747e748 41static char sccsid [] = "@(#)udb.c 8.3 (Berkeley) 8/25/93 (without USERDB)";
6f14531a
RG
42#endif
43#endif
44
45#ifdef USERDB
46
47#include <sys/time.h>
48#include <errno.h>
49#include <netdb.h>
50#include <db.h>
51
52/*
53** UDB.C -- interface between sendmail and Berkeley User Data Base.
54**
55** This depends on the 4.4BSD db package.
56*/
57
58
59struct udbent
60{
61 char *udb_spec; /* string version of spec */
62 int udb_type; /* type of entry */
63 char *udb_default; /* default host for outgoing mail */
64 union
65 {
66 /* type UE_REMOTE -- do remote call for lookup */
67 struct
68 {
69 struct sockaddr_in _udb_addr; /* address */
70 int _udb_timeout; /* timeout */
71 } udb_remote;
72#define udb_addr udb_u.udb_remote._udb_addr
73#define udb_timeout udb_u.udb_remote._udb_timeout
74
75 /* type UE_FORWARD -- forward message to remote */
76 struct
77 {
78 char *_udb_fwdhost; /* name of forward host */
79 } udb_forward;
80#define udb_fwdhost udb_u.udb_forward._udb_fwdhost
81
82 /* type UE_FETCH -- lookup in local database */
83 struct
84 {
85 char *_udb_dbname; /* pathname of database */
86 DB *_udb_dbp; /* open database ptr */
87 } udb_lookup;
88#define udb_dbname udb_u.udb_lookup._udb_dbname
89#define udb_dbp udb_u.udb_lookup._udb_dbp
90 } udb_u;
91};
92
93#define UDB_EOLIST 0 /* end of list */
94#define UDB_SKIP 1 /* skip this entry */
95#define UDB_REMOTE 2 /* look up in remote database */
96#define UDB_DBFETCH 3 /* look up in local database */
97#define UDB_FORWARD 4 /* forward to remote host */
98
99#define MAXUDBENT 10 /* maximum number of UDB entries */
100
101
102struct option
103{
104 char *name;
105 char *val;
106};
107\f/*
108** UDBEXPAND -- look up user in database and expand
109**
110** Parameters:
111** a -- address to expand.
112** sendq -- pointer to head of sendq to put the expansions in.
113**
114** Returns:
115** EX_TEMPFAIL -- if something "odd" happened -- probably due
116** to accessing a file on an NFS server that is down.
117** EX_OK -- otherwise.
118**
119** Side Effects:
120** Modifies sendq.
121*/
122
123int UdbPort = 1616;
124int UdbTimeout = 10;
125
126struct udbent UdbEnts[MAXUDBENT + 1];
127int UdbSock = -1;
128bool UdbInitialized = FALSE;
129
130int
131udbexpand(a, sendq, e)
132 register ADDRESS *a;
133 ADDRESS **sendq;
134 register ENVELOPE *e;
135{
136 int i;
137 register char *p;
138 DBT key;
139 DBT info;
140 bool breakout;
141 register struct udbent *up;
142 int keylen;
143 int naddrs;
144 char keybuf[MAXKEY];
145 char buf[BUFSIZ];
146
147 if (tTd(28, 1))
148 printf("udbexpand(%s)\n", a->q_paddr);
149
150 /* make certain we are supposed to send to this address */
151 if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
152 return EX_OK;
153 e->e_to = a->q_paddr;
154
155 /* on first call, locate the database */
156 if (!UdbInitialized)
157 {
158 extern int _udbx_init();
159
160 if (_udbx_init() == EX_TEMPFAIL)
161 return EX_TEMPFAIL;
162 }
163
164 /* short circuit the process if no chance of a match */
165 if (UdbSpec == NULL || UdbSpec[0] == '\0')
166 return EX_OK;
167
168 /* if name is too long, assume it won't match */
169 if (strlen(a->q_user) > sizeof keybuf - 12)
170 return EX_OK;
171
172 /* if name begins with a colon, it indicates our metadata */
173 if (a->q_user[0] == ':')
174 return EX_OK;
175
176 /* build actual database key */
177 (void) strcpy(keybuf, a->q_user);
178 (void) strcat(keybuf, ":maildrop");
179 keylen = strlen(keybuf);
180
181 breakout = FALSE;
182 for (up = UdbEnts; !breakout; up++)
183 {
184 char *user;
185
186 /*
187 ** Select action based on entry type.
188 **
189 ** On dropping out of this switch, "class" should
190 ** explain the type of the data, and "user" should
191 ** contain the user information.
192 */
193
194 switch (up->udb_type)
195 {
196 case UDB_DBFETCH:
197 key.data = keybuf;
198 key.size = keylen;
199 if (tTd(28, 80))
d747e748
JH
200 printf("udbexpand: trying %s (%d)\n",
201 keybuf, keylen);
6f14531a
RG
202 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
203 if (i > 0 || info.size <= 0)
204 {
205 if (tTd(28, 2))
d747e748
JH
206 printf("udbexpand: no match on %s (%d)\n",
207 keybuf, keylen);
6f14531a
RG
208 continue;
209 }
210 if (tTd(28, 80))
211 printf("udbexpand: match %.*s: %.*s\n",
212 key.size, key.data, info.size, info.data);
213
214 naddrs = 0;
215 a->q_flags &= ~QSELFREF;
216 while (i == 0 && key.size == keylen &&
217 bcmp(key.data, keybuf, keylen) == 0)
218 {
219 if (bitset(EF_VRFYONLY, e->e_flags))
220 {
221 a->q_flags |= QVERIFIED;
222 e->e_nrcpts++;
223 return EX_OK;
224 }
225
226 breakout = TRUE;
227 if (info.size < sizeof buf)
228 user = buf;
229 else
230 user = xalloc(info.size + 1);
231 bcopy(info.data, user, info.size);
232 user[info.size] = '\0';
233
234 message("expanded to %s", user);
235#ifdef LOG
236 if (LogLevel >= 10)
237 syslog(LOG_INFO, "%s: expand %s => %s",
238 e->e_id, e->e_to, user);
239#endif
240 AliasLevel++;
241 naddrs += sendtolist(user, a, sendq, e);
242 AliasLevel--;
243
244 if (user != buf)
245 free(user);
246
247 /* get the next record */
248 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
249 }
250
251 /* if nothing ever matched, try next database */
252 if (!breakout)
253 continue;
254
255 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
256 {
257 if (tTd(28, 5))
258 {
259 printf("udbexpand: QDONTSEND ");
260 printaddr(a, FALSE);
261 }
262 a->q_flags |= QDONTSEND;
263 }
264 if (i < 0)
265 {
266 syserr("udbexpand: db-get %.*s stat %d",
267 key.size, key.data, i);
268 return EX_TEMPFAIL;
269 }
270
271 /*
272 ** If this address has a -request address, reflect
273 ** it into the envelope.
274 */
275
276 (void) strcpy(keybuf, a->q_user);
277 (void) strcat(keybuf, ":mailsender");
278 keylen = strlen(keybuf);
279 key.data = keybuf;
280 key.size = keylen;
281 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
282 if (i != 0 || info.size <= 0)
283 break;
284 a->q_owner = xalloc(info.size + 1);
285 bcopy(info.data, a->q_owner, info.size);
286 a->q_owner[info.size] = '\0';
287 break;
288
289 case UDB_REMOTE:
290 /* not yet implemented */
291 continue;
292
293 case UDB_FORWARD:
294 if (bitset(EF_VRFYONLY, e->e_flags))
295 return EX_OK;
296 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
297 if (i < sizeof buf)
298 user = buf;
299 else
300 user = xalloc(i + 1);
301 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
302 message("expanded to %s", user);
303 a->q_flags &= ~QSELFREF;
304 AliasLevel++;
305 naddrs = sendtolist(user, a, sendq, e);
306 AliasLevel--;
307 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
308 {
309 if (tTd(28, 5))
310 {
311 printf("udbexpand: QDONTSEND ");
312 printaddr(a, FALSE);
313 }
314 a->q_flags |= QDONTSEND;
315 }
316 if (user != buf)
317 free(user);
318 breakout = TRUE;
319 break;
320
321 case UDB_EOLIST:
322 breakout = TRUE;
323 continue;
324
325 default:
326 /* unknown entry type */
327 continue;
328 }
329 }
330 return EX_OK;
331}
332\f/*
333** UDBSENDER -- return canonical external name of sender, given local name
334**
335** Parameters:
336** sender -- the name of the sender on the local machine.
337**
338** Returns:
339** The external name for this sender, if derivable from the
340** database.
341** NULL -- if nothing is changed from the database.
342**
343** Side Effects:
344** none.
345*/
346
347char *
348udbsender(sender)
349 char *sender;
d747e748
JH
350{
351 extern char *udbmatch();
352
353 return udbmatch(sender, "mailname");
354}
355
356
357char *
358udbmatch(user, field)
359 char *user;
360 char *field;
6f14531a
RG
361{
362 register char *p;
363 register struct udbent *up;
364 int i;
365 int keylen;
366 DBT key, info;
367 char keybuf[MAXKEY];
368
369 if (tTd(28, 1))
d747e748 370 printf("udbmatch(%s, %s)\n", user, field);
6f14531a
RG
371
372 if (!UdbInitialized)
373 {
374 if (_udbx_init() == EX_TEMPFAIL)
375 return NULL;
376 }
377
378 /* short circuit if no spec */
379 if (UdbSpec == NULL || UdbSpec[0] == '\0')
380 return NULL;
381
382 /* long names can never match and are a pain to deal with */
d747e748 383 if ((strlen(user) + strlen(field)) > sizeof keybuf - 4)
6f14531a
RG
384 return NULL;
385
386 /* names beginning with colons indicate metadata */
d747e748 387 if (user[0] == ':')
6f14531a
RG
388 return NULL;
389
390 /* build database key */
d747e748
JH
391 (void) strcpy(keybuf, user);
392 (void) strcat(keybuf, ":");
393 (void) strcat(keybuf, field);
6f14531a
RG
394 keylen = strlen(keybuf);
395
396 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
397 {
398 /*
399 ** Select action based on entry type.
400 */
401
402 switch (up->udb_type)
403 {
404 case UDB_DBFETCH:
405 key.data = keybuf;
406 key.size = keylen;
407 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
408 if (i != 0 || info.size <= 0)
409 {
410 if (tTd(28, 2))
d747e748
JH
411 printf("udbmatch: no match on %s (%d)\n",
412 keybuf, keylen);
6f14531a
RG
413 continue;
414 }
415
416 p = xalloc(info.size + 1);
417 bcopy(info.data, p, info.size);
418 p[info.size] = '\0';
419 if (tTd(28, 1))
d747e748 420 printf("udbmatch ==> %s\n", p);
6f14531a
RG
421 return p;
422 }
423 }
424
d747e748
JH
425 if (strcmp(field, "mailname") != 0)
426 return NULL;
427
6f14531a
RG
428 /*
429 ** Nothing yet. Search again for a default case. But only
430 ** use it if we also have a forward (:maildrop) pointer already
431 ** in the database.
432 */
433
434 /* build database key */
d747e748 435 (void) strcpy(keybuf, user);
6f14531a
RG
436 (void) strcat(keybuf, ":maildrop");
437 keylen = strlen(keybuf);
438
439 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
440 {
441 switch (up->udb_type)
442 {
443 case UDB_DBFETCH:
444 /* get the default case for this database */
445 if (up->udb_default == NULL)
446 {
447 key.data = ":default:mailname";
448 key.size = strlen(key.data);
449 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
450 if (i != 0 || info.size <= 0)
451 {
452 /* no default case */
453 up->udb_default = "";
454 continue;
455 }
456
457 /* save the default case */
458 up->udb_default = xalloc(info.size + 1);
459 bcopy(info.data, up->udb_default, info.size);
460 up->udb_default[info.size] = '\0';
461 }
462 else if (up->udb_default[0] == '\0')
463 continue;
464
465 /* we have a default case -- verify user:maildrop */
466 key.data = keybuf;
467 key.size = keylen;
468 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
469 if (i != 0 || info.size <= 0)
470 {
471 /* nope -- no aliasing for this user */
472 continue;
473 }
474
475 /* they exist -- build the actual address */
d747e748
JH
476 p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
477 (void) strcpy(p, user);
6f14531a
RG
478 (void) strcat(p, "@");
479 (void) strcat(p, up->udb_default);
480 if (tTd(28, 1))
d747e748 481 printf("udbmatch ==> %s\n", p);
6f14531a
RG
482 return p;
483 }
484 }
485
486 /* still nothing.... too bad */
487 return NULL;
488}
489\f/*
490** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
491**
492** Parameters:
493** none.
494**
495** Returns:
496** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
497** database due to a host being down or some similar
498** (recoverable) situation.
499** EX_OK -- otherwise.
500**
501** Side Effects:
502** Fills in the UdbEnts structure from UdbSpec.
503*/
504
505#define MAXUDBOPTS 27
506
507int
508_udbx_init()
509{
510 register char *p;
511 int i;
512 register struct udbent *up;
513 char buf[BUFSIZ];
514
515 if (UdbInitialized)
516 return EX_OK;
517
518# ifdef UDB_DEFAULT_SPEC
519 if (UdbSpec == NULL)
520 UdbSpec = UDB_DEFAULT_SPEC;
521# endif
522
523 p = UdbSpec;
524 up = UdbEnts;
525 while (p != NULL)
526 {
527 char *spec;
528 auto int rcode;
529 int nopts;
530 int nmx;
531 register struct hostent *h;
532 char *mxhosts[MAXMXHOSTS + 1];
533 struct option opts[MAXUDBOPTS + 1];
534
535 while (*p == ' ' || *p == '\t' || *p == ',')
536 p++;
537 if (*p == '\0')
538 break;
539 spec = p;
540 p = strchr(p, ',');
541 if (p != NULL)
542 *p++ = '\0';
543
544 /* extract options */
545 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
546
547 /*
548 ** Decode database specification.
549 **
550 ** In the sendmail tradition, the leading character
551 ** defines the semantics of the rest of the entry.
552 **
553 ** +hostname -- send a datagram to the udb server
554 ** on host "hostname" asking for the
555 ** home mail server for this user.
556 ** *hostname -- similar to +hostname, except that the
557 ** hostname is searched as an MX record;
558 ** resulting hosts are searched as for
559 ** +mxhostname. If no MX host is found,
560 ** this is the same as +hostname.
561 ** @hostname -- forward email to the indicated host.
562 ** This should be the last in the list,
563 ** since it always matches the input.
564 ** /dbname -- search the named database on the local
565 ** host using the Berkeley db package.
566 */
567
568 switch (*spec)
569 {
570 case '+': /* search remote database */
571 case '*': /* search remote database (expand MX) */
572 if (*spec == '*')
573 {
574#ifdef NAMED_BIND
575 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
576#else
577 mxhosts[0] = spec + 1;
578 nmx = 1;
579 rcode = 0;
580#endif
581 if (tTd(28, 16))
582 {
583 int i;
584
585 printf("getmxrr(%s): %d", spec + 1, nmx);
586 for (i = 0; i <= nmx; i++)
587 printf(" %s", mxhosts[i]);
588 printf("\n");
589 }
590 }
591 else
592 {
593 nmx = 1;
594 mxhosts[0] = spec + 1;
595 }
596
597 for (i = 0; i < nmx; i++)
598 {
599 h = gethostbyname(mxhosts[i]);
600 if (h == NULL)
601 continue;
602 up->udb_type = UDB_REMOTE;
603 up->udb_addr.sin_family = h->h_addrtype;
604 bcopy(h->h_addr_list[0],
605 (char *) &up->udb_addr.sin_addr,
606 h->h_length);
607 up->udb_addr.sin_port = UdbPort;
608 up->udb_timeout = UdbTimeout;
609 up++;
610 }
611
612 /* set up a datagram socket */
613 if (UdbSock < 0)
614 {
615 UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
616 (void) fcntl(UdbSock, F_SETFD, 1);
617 }
618 break;
619
620 case '@': /* forward to remote host */
621 up->udb_type = UDB_FORWARD;
622 up->udb_fwdhost = spec + 1;
623 up++;
624 break;
625
626 case '/': /* look up remote name */
627 up->udb_dbname = spec;
628 errno = 0;
629 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
630 if (up->udb_dbp == NULL)
631 {
632 if (errno != ENOENT && errno != EACCES)
633 {
634#ifdef LOG
635 if (LogLevel > 2)
636 syslog(LOG_ERR, "dbopen(%s): %s",
637 spec, errstring(errno));
638#endif
639 up->udb_type = UDB_EOLIST;
640 goto tempfail;
641 }
642 break;
643 }
644 up->udb_type = UDB_DBFETCH;
645 up++;
646 break;
647 }
648 }
649 up->udb_type = UDB_EOLIST;
650
651 if (tTd(28, 4))
652 {
653 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
654 {
655 switch (up->udb_type)
656 {
657 case UDB_REMOTE:
658 printf("REMOTE: addr %s, timeo %d\n",
659 anynet_ntoa((SOCKADDR *) &up->udb_addr),
660 up->udb_timeout);
661 break;
662
663 case UDB_DBFETCH:
664 printf("FETCH: file %s\n",
665 up->udb_dbname);
666 break;
667
668 case UDB_FORWARD:
669 printf("FORWARD: host %s\n",
670 up->udb_fwdhost);
671 break;
672
673 default:
674 printf("UNKNOWN\n");
675 break;
676 }
677 }
678 }
679
680 UdbInitialized = TRUE;
681 errno = 0;
682 return EX_OK;
683
684 /*
685 ** On temporary failure, back out anything we've already done
686 */
687
688 tempfail:
689 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
690 {
691 if (up->udb_type == UDB_DBFETCH)
692 {
693 (*up->udb_dbp->close)(up->udb_dbp);
694 }
695 }
696 return EX_TEMPFAIL;
697}
698
699int
700_udb_parsespec(udbspec, opt, maxopts)
701 char *udbspec;
702 struct option opt[];
703 int maxopts;
704{
705 register char *spec;
706 register char *spec_end;
707 register int optnum;
708
709 spec_end = strchr(udbspec, ':');
710 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
711 {
712 register char *p;
713
714 while (isascii(*spec) && isspace(*spec))
715 spec++;
716 spec_end = strchr(spec, ':');
717 if (spec_end != NULL)
718 *spec_end++ = '\0';
719
720 opt[optnum].name = spec;
721 opt[optnum].val = NULL;
722 p = strchr(spec, '=');
723 if (p != NULL)
724 opt[optnum].val = ++p;
725 }
726 return optnum;
727}
728
729#else /* not USERDB */
730
731int
732udbexpand(a, sendq, e)
733 ADDRESS *a;
734 ADDRESS **sendq;
735 ENVELOPE *e;
736{
737 return EX_OK;
738}
739
740#endif /* USERDB */