summaryrefslogtreecommitdiffstats
path: root/src/smtpd/smtpd_resolve.c
blob: 1dd691449ce6d55c88407b0fafedda366f3bb506 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*++
/* NAME
/*	smtpd_resolve 3
/* SUMMARY
/*	caching resolve client
/* SYNOPSIS
/*	#include <smtpd_resolve.h>
/*
/*	void	smtpd_resolve_init(cache_size)
/*	int	cache_size;
/*
/*	const RESOLVE_REPLY *smtpd_resolve_addr(sender, addr)
/*	const char *sender;
/*	const char *addr;
/* DESCRIPTION
/*	This module maintains a resolve client cache that persists
/*	across SMTP sessions (not process life times). Addresses
/*	are always resolved in local rewriting context.
/*
/*	smtpd_resolve_init() initializes the cache and must be
/*	called before the cache can be used. This function may also
/*	be called to flush the cache after an address class update.
/*
/*	smtpd_resolve_addr() resolves one address or returns
/*	a known result from cache.
/*
/*	Arguments:
/* .IP cache_size
/*	The requested cache size.
/* .IP sender
/*	The message sender, or null pointer.
/* .IP addr
/*	The address to resolve.
/* DIAGNOSTICS
/*	All errors are fatal.
/* BUGS
/*	The recipient address is always case folded to lowercase.
/*	Changing this requires great care, since the address is used
/*	for policy lookups.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*--*/

/* System library. */

#include <sys_defs.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <ctable.h>
#include <stringops.h>
#include <split_at.h>

/* Global library. */

#include <rewrite_clnt.h>
#include <resolve_clnt.h>
#include <mail_proto.h>

/* Application-specific. */

#include <smtpd_resolve.h>

static CTABLE *smtpd_resolve_cache;

#define STR(x) vstring_str(x)
#define SENDER_ADDR_JOIN_CHAR '\n'

/* resolve_pagein - page in an address resolver result */

static void *resolve_pagein(const char *sender_plus_addr, void *unused_context)
{
    const char myname[] = "resolve_pagein";
    static VSTRING *query;
    static VSTRING *junk;
    static VSTRING *sender_buf;
    RESOLVE_REPLY *reply;
    const char *sender;
    const char *addr;

    /*
     * Initialize on the fly.
     */
    if (query == 0) {
	query = vstring_alloc(10);
	junk = vstring_alloc(10);
	sender_buf = vstring_alloc(10);
    }

    /*
     * Initialize.
     */
    reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply));
    resolve_clnt_init(reply);

    /*
     * Split the sender and address.
     */
    vstring_strcpy(junk, sender_plus_addr);
    sender = STR(junk);
    if ((addr = split_at(STR(junk), SENDER_ADDR_JOIN_CHAR)) == 0)
	msg_panic("%s: bad search key: \"%s\"", myname, sender_plus_addr);

    /*
     * Resolve the address.
     */
    rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, sender, sender_buf);
    rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, addr, query);
    resolve_clnt_query_from(STR(sender_buf), STR(query), reply);
    vstring_strcpy(junk, STR(reply->recipient));
    casefold(reply->recipient, STR(junk));	/* XXX */

    /*
     * Save the result.
     */
    return ((void *) reply);
}

/* resolve_pageout - page out an address resolver result */

static void resolve_pageout(void *data, void *unused_context)
{
    RESOLVE_REPLY *reply = (RESOLVE_REPLY *) data;

    resolve_clnt_free(reply);
    myfree((void *) reply);
}

/* smtpd_resolve_init - set up global cache */

void    smtpd_resolve_init(int cache_size)
{

    /*
     * Flush a pre-existing cache. The smtpd_check test program requires this
     * after an address class change.
     */
    if (smtpd_resolve_cache)
	ctable_free(smtpd_resolve_cache);

    /*
     * Initialize the resolved address cache. Note: the cache persists across
     * SMTP sessions so we cannot make it dependent on session state.
     */
    smtpd_resolve_cache = ctable_create(cache_size, resolve_pagein,
					resolve_pageout, (void *) 0);
}

/* smtpd_resolve_addr - resolve cached address */

const RESOLVE_REPLY *smtpd_resolve_addr(const char *sender, const char *addr)
{
    static VSTRING *sender_plus_addr_buf;

    /*
     * Initialize on the fly.
     */
    if (sender_plus_addr_buf == 0)
	sender_plus_addr_buf = vstring_alloc(10);

    /*
     * Sanity check.
     */
    if (smtpd_resolve_cache == 0)
	msg_panic("smtpd_resolve_addr: missing initialization");

    /*
     * Reply from the read-through cache.
     */
    vstring_sprintf(sender_plus_addr_buf, "%s%c%s",
		    sender ? sender : RESOLVE_NULL_FROM,
		    SENDER_ADDR_JOIN_CHAR, addr);
    return (const RESOLVE_REPLY *)
	ctable_locate(smtpd_resolve_cache, STR(sender_plus_addr_buf));
}