1/*++
2/* NAME
3/*	smtp_unalias 3
4/* SUMMARY
5/*	replace host/domain alias by official name
6/* SYNOPSIS
7/*	#include "smtp.h"
8/*
9/*	const char *smtp_unalias_name(name)
10/*	const char *name;
11/*
12/*	VSTRING	*smtp_unalias_addr(result, addr)
13/*	VSTRING *result;
14/*	const char *addr;
15/* DESCRIPTION
16/*	smtp_unalias_name() looks up A or MX records for the specified
17/*	name and returns the official name provided in the reply. When
18/*	no A or MX record is found, the result is a copy of the input.
19/*	In order to improve performance, smtp_unalias_name() remembers
20/*	results in a private cache, so a name is looked up only once.
21/*
22/*	smtp_unalias_addr() returns the input address, which is in
23/*	RFC 821 quoted form, after replacing the domain part by the
24/*	official name as found by smtp_unalias_name(). When the input
25/*	contains no domain part, the result is a copy of the input.
26/* LICENSE
27/* .ad
28/* .fi
29/*	The Secure Mailer license must be distributed with this software.
30/* AUTHOR(S)
31/*	Wietse Venema
32/*	IBM T.J. Watson Research
33/*	P.O. Box 704
34/*	Yorktown Heights, NY 10598, USA
35/*--*/
36
37/* System library. */
38
39#include <sys_defs.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <stdlib.h>
44#include <netdb.h>
45#include <string.h>
46
47/* Utility library. */
48
49#include <htable.h>
50#include <vstring.h>
51#include <msg.h>
52
53/* DNS library. */
54
55#include <dns.h>
56
57/* Application-specific. */
58
59#include "smtp.h"
60
61static int smtp_unalias_flags;
62
63/* smtp_unalias_name - look up the official host or domain name. */
64
65const char *smtp_unalias_name(const char *name)
66{
67    static HTABLE *cache;
68    VSTRING *fqdn;
69    char   *result;
70
71    if (*name == '[')
72	return (name);
73
74    /*
75     * Initialize the cache on the fly. The smtp client is designed to exit
76     * after servicing a limited number of requests, so there is no need to
77     * prevent the cache from growing too large, or to expire old entries.
78     */
79    if (cache == 0)
80	cache = htable_create(10);
81
82    /*
83     * Look up the fqdn. If none is found use the query name instead, so that
84     * we won't lose time looking up the same bad name again.
85     */
86    if ((result = htable_find(cache, name)) == 0) {
87	fqdn = vstring_alloc(10);
88	if (dns_lookup_l(name, smtp_unalias_flags, (DNS_RR **) 0, fqdn,
89			     (VSTRING *) 0, DNS_REQ_FLAG_NONE, T_MX, T_A,
90#ifdef HAS_IPV6
91			     T_AAAA,
92#endif
93			     0) != DNS_OK)
94	    vstring_strcpy(fqdn, name);
95	htable_enter(cache, name, result = vstring_export(fqdn));
96    }
97    return (result);
98}
99
100/* smtp_unalias_addr - rewrite aliases in domain part of address */
101
102VSTRING *smtp_unalias_addr(VSTRING *result, const char *addr)
103{
104    char   *at;
105    const char *fqdn;
106
107    if ((at = strrchr(addr, '@')) == 0 || at[1] == 0) {
108	vstring_strcpy(result, addr);
109    } else {
110	fqdn = smtp_unalias_name(at + 1);
111	vstring_strncpy(result, addr, at - addr + 1);
112	vstring_strcat(result, fqdn);
113    }
114    return (result);
115}
116
117#ifdef TEST
118
119 /*
120  * Test program - read address from stdin, print result on stdout.
121  */
122
123#include <vstring_vstream.h>
124
125int     main(int unused_argc, char **unused_argv)
126{
127    VSTRING *addr = vstring_alloc(10);
128    VSTRING *result = vstring_alloc(10);
129
130    smtp_unalias_flags |= RES_DEBUG;
131
132    while (vstring_fgets_nonl(addr, VSTREAM_IN)) {
133	smtp_unalias_addr(result, vstring_str(addr));
134	vstream_printf("%s -> %s\n", vstring_str(addr), vstring_str(result));
135	vstream_fflush(VSTREAM_OUT);
136    }
137    vstring_free(addr);
138    vstring_free(result);
139    return (0);
140}
141
142#endif
143