Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / proxymap / proxymap.c
blob01ccbddc088b47244eb268b141e6d08f0b48b7e2
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* proxymap 8
6 /* SUMMARY
7 /* Postfix lookup table proxy server
8 /* SYNOPSIS
9 /* \fBproxymap\fR [generic Postfix daemon options]
10 /* DESCRIPTION
11 /* The \fBproxymap\fR(8) server provides read-only or read-write
12 /* table lookup service to Postfix processes. These services are
13 /* implemented with distinct service names: \fBproxymap\fR and
14 /* \fBproxywrite\fR, respectively. The purpose of these services is:
15 /* .IP \(bu
16 /* To overcome chroot restrictions. For example, a chrooted SMTP
17 /* server needs access to the system passwd file in order to
18 /* reject mail for non-existent local addresses, but it is not
19 /* practical to maintain a copy of the passwd file in the chroot
20 /* jail. The solution:
21 /* .sp
22 /* .nf
23 /* local_recipient_maps =
24 /* proxy:unix:passwd.byname $alias_maps
25 /* .fi
26 /* .IP \(bu
27 /* To consolidate the number of open lookup tables by sharing
28 /* one open table among multiple processes. For example, making
29 /* mysql connections from every Postfix daemon process results
30 /* in "too many connections" errors. The solution:
31 /* .sp
32 /* .nf
33 /* virtual_alias_maps =
34 /* proxy:mysql:/etc/postfix/virtual_alias.cf
35 /* .fi
36 /* .sp
37 /* The total number of connections is limited by the number of
38 /* proxymap server processes.
39 /* .IP \(bu
40 /* To provide single-updater functionality for lookup tables
41 /* that do not reliably support multiple writers (i.e. all
42 /* file-based tables).
43 /* .PP
44 /* The \fBproxymap\fR(8) server implements the following requests:
45 /* .IP "\fBopen\fR \fImaptype:mapname flags\fR"
46 /* Open the table with type \fImaptype\fR and name \fImapname\fR,
47 /* as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
48 /* dependent flags (to distinguish a fixed string table from a regular
49 /* expression table).
50 /* .IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
51 /* Look up the data stored under the requested key.
52 /* The reply is the request completion status code and
53 /* the lookup result value.
54 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
55 /* as with the \fBopen\fR request.
56 /* .IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
57 /* Update the data stored under the requested key.
58 /* The reply is the request completion status code.
59 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
60 /* as with the \fBopen\fR request.
61 /* .sp
62 /* To implement single-updater maps, specify a process limit
63 /* of 1 in the master.cf file entry for the \fBproxywrite\fR
64 /* service.
65 /* .sp
66 /* This request is supported in Postfix 2.5 and later.
67 /* .IP "\fBdelete\fR \fImaptype:mapname flags key\fR"
68 /* Delete the data stored under the requested key.
69 /* The reply is the request completion status code.
70 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
71 /* as with the \fBopen\fR request.
72 /* .sp
73 /* This request is supported in Postfix 2.5 and later.
74 /* .PP
75 /* The request completion status is one of OK, RETRY, NOKEY
76 /* (lookup failed because the key was not found), BAD (malformed
77 /* request) or DENY (the table is not approved for proxy read
78 /* or update access).
80 /* There is no \fBclose\fR command, nor are tables implicitly closed
81 /* when a client disconnects. The purpose is to share tables among
82 /* multiple client processes.
83 /* SERVER PROCESS MANAGEMENT
84 /* .ad
85 /* .fi
86 /* \fBproxymap\fR(8) servers run under control by the Postfix
87 /* \fBmaster\fR(8)
88 /* server. Each server can handle multiple simultaneous connections.
89 /* When all servers are busy while a client connects, the \fBmaster\fR(8)
90 /* creates a new \fBproxymap\fR(8) server process, provided that the
91 /* process limit is not exceeded.
92 /* Each server terminates after serving at least \fB$max_use\fR clients
93 /* or after \fB$max_idle\fR seconds of idle time.
94 /* SECURITY
95 /* .ad
96 /* .fi
97 /* The \fBproxymap\fR(8) server opens only tables that are
98 /* approved via the \fBproxy_read_maps\fR or \fBproxy_write_maps\fR
99 /* configuration parameters, does not talk to
100 /* users, and can run at fixed low privilege, chrooted or not.
101 /* However, running the proxymap server chrooted severely limits
102 /* usability, because it can open only chrooted tables.
104 /* The \fBproxymap\fR(8) server is not a trusted daemon process, and must
105 /* not be used to look up sensitive information such as user or
106 /* group IDs, mailbox file/directory names or external commands.
108 /* In Postfix version 2.2 and later, the proxymap client recognizes
109 /* requests to access a table for security-sensitive purposes,
110 /* and opens the table directly. This allows the same main.cf
111 /* setting to be used by sensitive and non-sensitive processes.
113 /* Postfix-writable data files should be stored under a dedicated
114 /* directory that is writable only by the Postfix mail system,
115 /* such as the Postfix-owned \fBdata_directory\fR.
117 /* In particular, Postfix-writable files should never exist
118 /* in root-owned directories. That would open up a particular
119 /* type of security hole where ownership of a file or directory
120 /* does not match the provider of its content.
121 /* DIAGNOSTICS
122 /* Problems and transactions are logged to \fBsyslogd\fR(8).
123 /* BUGS
124 /* The \fBproxymap\fR(8) server provides service to multiple clients,
125 /* and must therefore not be used for tables that have high-latency
126 /* lookups.
128 /* The \fBproxymap\fR(8) read-write service does not explicitly
129 /* close lookup tables (even if it did, this could not be relied on,
130 /* because the process may be terminated between table updates).
131 /* The read-write service should therefore not be used with tables that
132 /* leave persistent storage in an inconsistent state between
133 /* updates (for example, CDB). Tables that support "sync on
134 /* update" should be safe (for example, Berkeley DB) as should
135 /* tables that are implemented by a real DBMS.
136 /* CONFIGURATION PARAMETERS
137 /* .ad
138 /* .fi
139 /* On busy mail systems a long time may pass before
140 /* \fBproxymap\fR(8) relevant
141 /* changes to \fBmain.cf\fR are picked up. Use the command
142 /* "\fBpostfix reload\fR" to speed up a change.
144 /* The text below provides only a parameter summary. See
145 /* \fBpostconf\fR(5) for more details including examples.
146 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
147 /* The default location of the Postfix main.cf and master.cf
148 /* configuration files.
149 /* .IP "\fBdata_directory (see 'postconf -d' output)\fR"
150 /* The directory with Postfix-writable data files (for example:
151 /* caches, pseudo-random numbers).
152 /* .IP "\fBdaemon_timeout (18000s)\fR"
153 /* How much time a Postfix daemon process may take to handle a
154 /* request before it is terminated by a built-in watchdog timer.
155 /* .IP "\fBipc_timeout (3600s)\fR"
156 /* The time limit for sending or receiving information over an internal
157 /* communication channel.
158 /* .IP "\fBmax_idle (100s)\fR"
159 /* The maximum amount of time that an idle Postfix daemon process waits
160 /* for an incoming connection before terminating voluntarily.
161 /* .IP "\fBmax_use (100)\fR"
162 /* The maximal number of incoming connections that a Postfix daemon
163 /* process will service before terminating voluntarily.
164 /* .IP "\fBprocess_id (read-only)\fR"
165 /* The process ID of a Postfix command or daemon process.
166 /* .IP "\fBprocess_name (read-only)\fR"
167 /* The process name of a Postfix command or daemon process.
168 /* .IP "\fBproxy_read_maps (see 'postconf -d' output)\fR"
169 /* The lookup tables that the \fBproxymap\fR(8) server is allowed to
170 /* access for the read-only service.
171 /* .PP
172 /* Available in Postfix 2.5 and later:
173 /* .IP "\fBdata_directory (see 'postconf -d' output)\fR"
174 /* The directory with Postfix-writable data files (for example:
175 /* caches, pseudo-random numbers).
176 /* .IP "\fBproxy_write_maps (see 'postconf -d' output)\fR"
177 /* The lookup tables that the \fBproxymap\fR(8) server is allowed to
178 /* access for the read-write service.
179 /* SEE ALSO
180 /* postconf(5), configuration parameters
181 /* master(5), generic daemon options
182 /* README FILES
183 /* .ad
184 /* .fi
185 /* Use "\fBpostconf readme_directory\fR" or
186 /* "\fBpostconf html_directory\fR" to locate this information.
187 /* .na
188 /* .nf
189 /* DATABASE_README, Postfix lookup table overview
190 /* LICENSE
191 /* .ad
192 /* .fi
193 /* The Secure Mailer license must be distributed with this software.
194 /* HISTORY
195 /* .ad
196 /* .fi
197 /* The proxymap service was introduced with Postfix 2.0.
198 /* AUTHOR(S)
199 /* Wietse Venema
200 /* IBM T.J. Watson Research
201 /* P.O. Box 704
202 /* Yorktown Heights, NY 10598, USA
203 /*--*/
205 /* System library. */
207 #include <sys_defs.h>
208 #include <string.h>
209 #include <stdlib.h>
210 #include <unistd.h>
212 /* Utility library. */
214 #include <msg.h>
215 #include <mymalloc.h>
216 #include <vstring.h>
217 #include <htable.h>
218 #include <stringops.h>
219 #include <dict.h>
221 /* Global library. */
223 #include <mail_conf.h>
224 #include <mail_params.h>
225 #include <mail_version.h>
226 #include <mail_proto.h>
227 #include <dict_proxy.h>
229 /* Server skeleton. */
231 #include <mail_server.h>
233 /* Application-specific. */
236 * XXX All but the last are needed here so that $name expansion dependencies
237 * aren't too broken. The fix is to gather all parameter default settings in
238 * one place.
240 char *var_local_rcpt_maps;
241 char *var_virt_alias_maps;
242 char *var_virt_alias_doms;
243 char *var_virt_mailbox_maps;
244 char *var_virt_mailbox_doms;
245 char *var_relay_rcpt_maps;
246 char *var_relay_domains;
247 char *var_canonical_maps;
248 char *var_send_canon_maps;
249 char *var_rcpt_canon_maps;
250 char *var_relocated_maps;
251 char *var_transport_maps;
252 char *var_proxy_read_maps;
253 char *var_proxy_write_maps;
256 * The pre-approved, pre-parsed list of maps.
258 static HTABLE *proxy_auth_maps;
261 * Shared and static to reduce memory allocation overhead.
263 static VSTRING *request;
264 static VSTRING *request_map;
265 static VSTRING *request_key;
266 static VSTRING *request_value;
267 static VSTRING *map_type_name_flags;
270 * Are we a proxy writer or not?
272 static int proxy_writer;
275 * Silly little macros.
277 #define STR(x) vstring_str(x)
278 #define VSTREQ(x,y) (strcmp(STR(x),y) == 0)
280 /* proxy_map_find - look up or open table */
282 static DICT *proxy_map_find(const char *map_type_name, int request_flags,
283 int *statp)
285 DICT *dict;
287 #define PROXY_COLON DICT_TYPE_PROXY ":"
288 #define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
289 #define READ_OPEN_FLAGS O_RDONLY
290 #define WRITE_OPEN_FLAGS (O_RDWR | O_CREAT)
293 * Canonicalize the map name. If the map is not on the approved list,
294 * deny the request.
296 #define PROXY_MAP_FIND_ERROR_RETURN(x) { *statp = (x); return (0); }
298 while (strncmp(map_type_name, PROXY_COLON, PROXY_COLON_LEN) == 0)
299 map_type_name += PROXY_COLON_LEN;
300 if (strchr(map_type_name, ':') == 0)
301 PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_BAD);
302 if (htable_locate(proxy_auth_maps, map_type_name) == 0) {
303 msg_warn("request for unapproved table: \"%s\"", map_type_name);
304 msg_warn("to approve this table for %s access, list %s:%s in %s:%s",
305 proxy_writer == 0 ? "read-only" : "read-write",
306 DICT_TYPE_PROXY, map_type_name, MAIN_CONF_FILE,
307 proxy_writer == 0 ? VAR_PROXY_READ_MAPS :
308 VAR_PROXY_WRITE_MAPS);
309 PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_DENY);
313 * Open one instance of a map for each combination of name+flags.
315 * Assume that a map instance can be shared among clients with different
316 * paranoia flag settings and with different map lookup flag settings.
318 * XXX The open() flags are passed implicitly, via the selection of the
319 * service name. For a more sophisticated interface, appropriate subsets
320 * of open() flags should be received directly from the client.
322 vstring_sprintf(map_type_name_flags, "%s:%s", map_type_name,
323 dict_flags_str(request_flags & DICT_FLAG_NP_INST_MASK));
324 if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
325 dict = dict_open(map_type_name, proxy_writer ?
326 WRITE_OPEN_FLAGS : READ_OPEN_FLAGS,
327 request_flags);
328 if (dict == 0)
329 msg_panic("proxy_map_find: dict_open null result");
330 dict_register(STR(map_type_name_flags), dict);
331 return (dict);
334 /* proxymap_lookup_service - remote lookup service */
336 static void proxymap_lookup_service(VSTREAM *client_stream)
338 int request_flags;
339 DICT *dict;
340 const char *reply_value;
341 int reply_status;
344 * Process the request.
346 if (attr_scan(client_stream, ATTR_FLAG_STRICT,
347 ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
348 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
349 ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
350 ATTR_TYPE_END) != 3) {
351 reply_status = PROXY_STAT_BAD;
352 reply_value = "";
353 } else if ((dict = proxy_map_find(STR(request_map), request_flags,
354 &reply_status)) == 0) {
355 reply_value = "";
356 } else if (dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
357 | (request_flags & DICT_FLAG_RQST_MASK)),
358 (reply_value = dict_get(dict, STR(request_key))) != 0) {
359 reply_status = PROXY_STAT_OK;
360 } else if (dict_errno == 0) {
361 reply_status = PROXY_STAT_NOKEY;
362 reply_value = "";
363 } else {
364 reply_status = PROXY_STAT_RETRY;
365 reply_value = "";
369 * Respond to the client.
371 attr_print(client_stream, ATTR_FLAG_NONE,
372 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
373 ATTR_TYPE_STR, MAIL_ATTR_VALUE, reply_value,
374 ATTR_TYPE_END);
377 /* proxymap_update_service - remote update service */
379 static void proxymap_update_service(VSTREAM *client_stream)
381 int request_flags;
382 DICT *dict;
383 int reply_status;
386 * Process the request.
388 * XXX We don't close maps, so we must turn on synchronous update to ensure
389 * that the on-disk data is in a consistent state between updates.
391 * XXX We ignore duplicates, because the proxymap server would abort
392 * otherwise.
394 if (attr_scan(client_stream, ATTR_FLAG_STRICT,
395 ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
396 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
397 ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
398 ATTR_TYPE_STR, MAIL_ATTR_VALUE, request_value,
399 ATTR_TYPE_END) != 4) {
400 reply_status = PROXY_STAT_BAD;
401 } else if (proxy_writer == 0) {
402 msg_warn("refusing %s update request on non-%s service",
403 STR(request_map), MAIL_SERVICE_PROXYWRITE);
404 reply_status = PROXY_STAT_DENY;
405 } else if ((dict = proxy_map_find(STR(request_map), request_flags,
406 &reply_status)) == 0) {
407 /* void */ ;
408 } else {
409 dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
410 | (request_flags & DICT_FLAG_RQST_MASK)
411 | DICT_FLAG_SYNC_UPDATE | DICT_FLAG_DUP_REPLACE);
412 dict_put(dict, STR(request_key), STR(request_value));
413 reply_status = PROXY_STAT_OK;
417 * Respond to the client.
419 attr_print(client_stream, ATTR_FLAG_NONE,
420 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
421 ATTR_TYPE_END);
424 /* proxymap_delete_service - remote delete service */
426 static void proxymap_delete_service(VSTREAM *client_stream)
428 int request_flags;
429 DICT *dict;
430 int reply_status;
433 * Process the request.
435 * XXX We don't close maps, so we must turn on synchronous update to ensure
436 * that the on-disk data is in a consistent state between updates.
438 if (attr_scan(client_stream, ATTR_FLAG_STRICT,
439 ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
440 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
441 ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
442 ATTR_TYPE_END) != 3) {
443 reply_status = PROXY_STAT_BAD;
444 } else if (proxy_writer == 0) {
445 msg_warn("refusing %s delete request on non-%s service",
446 STR(request_map), MAIL_SERVICE_PROXYWRITE);
447 reply_status = PROXY_STAT_DENY;
448 } else if ((dict = proxy_map_find(STR(request_map), request_flags,
449 &reply_status)) == 0) {
450 /* void */ ;
451 } else {
452 dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
453 | (request_flags & DICT_FLAG_RQST_MASK)
454 | DICT_FLAG_SYNC_UPDATE);
455 reply_status =
456 dict_del(dict, STR(request_key)) ? PROXY_STAT_OK : PROXY_STAT_NOKEY;
460 * Respond to the client.
462 attr_print(client_stream, ATTR_FLAG_NONE,
463 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
464 ATTR_TYPE_END);
467 /* proxymap_open_service - open remote lookup table */
469 static void proxymap_open_service(VSTREAM *client_stream)
471 int request_flags;
472 DICT *dict;
473 int reply_status;
474 int reply_flags;
477 * Process the request.
479 if (attr_scan(client_stream, ATTR_FLAG_STRICT,
480 ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
481 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
482 ATTR_TYPE_END) != 2) {
483 reply_status = PROXY_STAT_BAD;
484 reply_flags = 0;
485 } else if ((dict = proxy_map_find(STR(request_map), request_flags,
486 &reply_status)) == 0) {
487 reply_flags = 0;
488 } else {
489 reply_status = PROXY_STAT_OK;
490 reply_flags = dict->flags;
494 * Respond to the client.
496 attr_print(client_stream, ATTR_FLAG_NONE,
497 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
498 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, reply_flags,
499 ATTR_TYPE_END);
502 /* proxymap_service - perform service for client */
504 static void proxymap_service(VSTREAM *client_stream, char *unused_service,
505 char **argv)
509 * Sanity check. This service takes no command-line arguments.
511 if (argv[0])
512 msg_fatal("unexpected command-line argument: %s", argv[0]);
515 * This routine runs whenever a client connects to the socket dedicated
516 * to the proxymap service. All connection-management stuff is handled by
517 * the common code in multi_server.c.
519 if (attr_scan(client_stream,
520 ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
521 ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
522 ATTR_TYPE_END) == 1) {
523 if (VSTREQ(request, PROXY_REQ_LOOKUP)) {
524 proxymap_lookup_service(client_stream);
525 } else if (VSTREQ(request, PROXY_REQ_UPDATE)) {
526 proxymap_update_service(client_stream);
527 } else if (VSTREQ(request, PROXY_REQ_DELETE)) {
528 proxymap_delete_service(client_stream);
529 } else if (VSTREQ(request, PROXY_REQ_OPEN)) {
530 proxymap_open_service(client_stream);
531 } else {
532 msg_warn("unrecognized request: \"%s\", ignored", STR(request));
533 attr_print(client_stream, ATTR_FLAG_NONE,
534 ATTR_TYPE_INT, MAIL_ATTR_STATUS, PROXY_STAT_BAD,
535 ATTR_TYPE_END);
538 vstream_fflush(client_stream);
541 /* dict_proxy_open - intercept remote map request from inside library */
543 DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
545 if (msg_verbose)
546 msg_info("dict_proxy_open(%s, 0%o, 0%o) called from internal routine",
547 map, open_flags, dict_flags);
548 while (strncmp(map, PROXY_COLON, PROXY_COLON_LEN) == 0)
549 map += PROXY_COLON_LEN;
550 return (dict_open(map, open_flags, dict_flags));
553 /* post_jail_init - initialization after privilege drop */
555 static void post_jail_init(char *service_name, char **unused_argv)
557 const char *sep = ", \t\r\n";
558 char *saved_filter;
559 char *bp;
560 char *type_name;
563 * Are we proxy writer?
565 if (strcmp(service_name, MAIL_SERVICE_PROXYWRITE) == 0)
566 proxy_writer = 1;
567 else if (strcmp(service_name, MAIL_SERVICE_PROXYMAP) != 0)
568 msg_fatal("service name must be one of %s or %s",
569 MAIL_SERVICE_PROXYMAP, MAIL_SERVICE_PROXYMAP);
572 * Pre-allocate buffers.
574 request = vstring_alloc(10);
575 request_map = vstring_alloc(10);
576 request_key = vstring_alloc(10);
577 request_value = vstring_alloc(10);
578 map_type_name_flags = vstring_alloc(10);
581 * Prepare the pre-approved list of proxied tables.
583 saved_filter = bp = mystrdup(proxy_writer ? var_proxy_write_maps :
584 var_proxy_read_maps);
585 proxy_auth_maps = htable_create(13);
586 while ((type_name = mystrtok(&bp, sep)) != 0) {
587 if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
588 continue;
589 do {
590 type_name += PROXY_COLON_LEN;
591 } while (!strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN));
592 if (strchr(type_name, ':') != 0
593 && htable_locate(proxy_auth_maps, type_name) == 0)
594 (void) htable_enter(proxy_auth_maps, type_name, (char *) 0);
596 myfree(saved_filter);
599 * This process is called by clients that already enforce the max_idle
600 * time, so we don't have to do it another time.
602 var_idle_limit = 1;
605 * Never, ever, get killed by a master signal, as that could corrupt a
606 * persistent database when we're in the middle of an update.
608 if (proxy_writer != 0)
609 setsid();
612 /* pre_accept - see if tables have changed */
614 static void pre_accept(char *unused_name, char **unused_argv)
616 const char *table;
618 if (proxy_writer == 0 && (table = dict_changed_name()) != 0) {
619 msg_info("table %s has changed -- restarting", table);
620 exit(0);
624 MAIL_VERSION_STAMP_DECLARE;
626 /* main - pass control to the multi-threaded skeleton */
628 int main(int argc, char **argv)
630 static const CONFIG_STR_TABLE str_table[] = {
631 VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
632 VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
633 VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
634 VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
635 VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0,
636 VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
637 VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
638 VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
639 VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
640 VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
641 VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
642 VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
643 VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
644 VAR_PROXY_WRITE_MAPS, DEF_PROXY_WRITE_MAPS, &var_proxy_write_maps, 0, 0,
649 * Fingerprint executables and core dumps.
651 MAIL_VERSION_STAMP_ALLOCATE;
653 multi_server_main(argc, argv, proxymap_service,
654 MAIL_SERVER_STR_TABLE, str_table,
655 MAIL_SERVER_POST_INIT, post_jail_init,
656 MAIL_SERVER_PRE_ACCEPT, pre_accept,
657 /* XXX MAIL_SERVER_SOLITARY if proxywrite */