Postfix3.3.1
proxymap.c
[詳解]
1 /*++
2 /* NAME
3 /* proxymap 8
4 /* SUMMARY
5 /* Postfix lookup table proxy server
6 /* SYNOPSIS
7 /* \fBproxymap\fR [generic Postfix daemon options]
8 /* DESCRIPTION
9 /* The \fBproxymap\fR(8) server provides read-only or read-write
10 /* table lookup service to Postfix processes. These services are
11 /* implemented with distinct service names: \fBproxymap\fR and
12 /* \fBproxywrite\fR, respectively. The purpose of these services is:
13 /* .IP \(bu
14 /* To overcome chroot restrictions. For example, a chrooted SMTP
15 /* server needs access to the system passwd file in order to
16 /* reject mail for non-existent local addresses, but it is not
17 /* practical to maintain a copy of the passwd file in the chroot
18 /* jail. The solution:
19 /* .sp
20 /* .nf
21 /* local_recipient_maps =
22 /* proxy:unix:passwd.byname $alias_maps
23 /* .fi
24 /* .IP \(bu
25 /* To consolidate the number of open lookup tables by sharing
26 /* one open table among multiple processes. For example, making
27 /* mysql connections from every Postfix daemon process results
28 /* in "too many connections" errors. The solution:
29 /* .sp
30 /* .nf
31 /* virtual_alias_maps =
32 /* proxy:mysql:/etc/postfix/virtual_alias.cf
33 /* .fi
34 /* .sp
35 /* The total number of connections is limited by the number of
36 /* proxymap server processes.
37 /* .IP \(bu
38 /* To provide single-updater functionality for lookup tables
39 /* that do not reliably support multiple writers (i.e. all
40 /* file-based tables).
41 /* .PP
42 /* The \fBproxymap\fR(8) server implements the following requests:
43 /* .IP "\fBopen\fR \fImaptype:mapname flags\fR"
44 /* Open the table with type \fImaptype\fR and name \fImapname\fR,
45 /* as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
46 /* dependent flags (to distinguish a fixed string table from a regular
47 /* expression table).
48 /* .IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
49 /* Look up the data stored under the requested key.
50 /* The reply is the request completion status code and
51 /* the lookup result value.
52 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
53 /* as with the \fBopen\fR request.
54 /* .IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
55 /* Update the data stored under the requested key.
56 /* The reply is the request completion status code.
57 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
58 /* as with the \fBopen\fR request.
59 /* .sp
60 /* To implement single-updater maps, specify a process limit
61 /* of 1 in the master.cf file entry for the \fBproxywrite\fR
62 /* service.
63 /* .sp
64 /* This request is supported in Postfix 2.5 and later.
65 /* .IP "\fBdelete\fR \fImaptype:mapname flags key\fR"
66 /* Delete the data stored under the requested key.
67 /* The reply is the request completion status code.
68 /* The \fImaptype:mapname\fR and \fIflags\fR are the same
69 /* as with the \fBopen\fR request.
70 /* .sp
71 /* This request is supported in Postfix 2.5 and later.
72 /* .IP "\fBsequence\fR \fImaptype:mapname flags function\fR"
73 /* Iterate over the specified database. The \fIfunction\fR
74 /* is one of DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
75 /* The reply is the request completion status code and
76 /* a lookup key and result value, if found.
77 /* .sp
78 /* This request is supported in Postfix 2.9 and later.
79 /* .PP
80 /* The request completion status is one of OK, RETRY, NOKEY
81 /* (lookup failed because the key was not found), BAD (malformed
82 /* request) or DENY (the table is not approved for proxy read
83 /* or update access).
84 /*
85 /* There is no \fBclose\fR command, nor are tables implicitly closed
86 /* when a client disconnects. The purpose is to share tables among
87 /* multiple client processes.
88 /* SERVER PROCESS MANAGEMENT
89 /* .ad
90 /* .fi
91 /* \fBproxymap\fR(8) servers run under control by the Postfix
92 /* \fBmaster\fR(8)
93 /* server. Each server can handle multiple simultaneous connections.
94 /* When all servers are busy while a client connects, the \fBmaster\fR(8)
95 /* creates a new \fBproxymap\fR(8) server process, provided that the
96 /* process limit is not exceeded.
97 /* Each server terminates after serving at least \fB$max_use\fR clients
98 /* or after \fB$max_idle\fR seconds of idle time.
99 /* SECURITY
100 /* .ad
101 /* .fi
102 /* The \fBproxymap\fR(8) server opens only tables that are
103 /* approved via the \fBproxy_read_maps\fR or \fBproxy_write_maps\fR
104 /* configuration parameters, does not talk to
105 /* users, and can run at fixed low privilege, chrooted or not.
106 /* However, running the proxymap server chrooted severely limits
107 /* usability, because it can open only chrooted tables.
108 /*
109 /* The \fBproxymap\fR(8) server is not a trusted daemon process, and must
110 /* not be used to look up sensitive information such as UNIX user or
111 /* group IDs, mailbox file/directory names or external commands.
112 /*
113 /* In Postfix version 2.2 and later, the proxymap client recognizes
114 /* requests to access a table for security-sensitive purposes,
115 /* and opens the table directly. This allows the same main.cf
116 /* setting to be used by sensitive and non-sensitive processes.
117 /*
118 /* Postfix-writable data files should be stored under a dedicated
119 /* directory that is writable only by the Postfix mail system,
120 /* such as the Postfix-owned \fBdata_directory\fR.
121 /*
122 /* In particular, Postfix-writable files should never exist
123 /* in root-owned directories. That would open up a particular
124 /* type of security hole where ownership of a file or directory
125 /* does not match the provider of its content.
126 /* DIAGNOSTICS
127 /* Problems and transactions are logged to \fBsyslogd\fR(8).
128 /* BUGS
129 /* The \fBproxymap\fR(8) server provides service to multiple clients,
130 /* and must therefore not be used for tables that have high-latency
131 /* lookups.
132 /*
133 /* The \fBproxymap\fR(8) read-write service does not explicitly
134 /* close lookup tables (even if it did, this could not be relied on,
135 /* because the process may be terminated between table updates).
136 /* The read-write service should therefore not be used with tables that
137 /* leave persistent storage in an inconsistent state between
138 /* updates (for example, CDB). Tables that support "sync on
139 /* update" should be safe (for example, Berkeley DB) as should
140 /* tables that are implemented by a real DBMS.
141 /* CONFIGURATION PARAMETERS
142 /* .ad
143 /* .fi
144 /* On busy mail systems a long time may pass before
145 /* \fBproxymap\fR(8) relevant
146 /* changes to \fBmain.cf\fR are picked up. Use the command
147 /* "\fBpostfix reload\fR" to speed up a change.
148 /*
149 /* The text below provides only a parameter summary. See
150 /* \fBpostconf\fR(5) for more details including examples.
151 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
152 /* The default location of the Postfix main.cf and master.cf
153 /* configuration files.
154 /* .IP "\fBdata_directory (see 'postconf -d' output)\fR"
155 /* The directory with Postfix-writable data files (for example:
156 /* caches, pseudo-random numbers).
157 /* .IP "\fBdaemon_timeout (18000s)\fR"
158 /* How much time a Postfix daemon process may take to handle a
159 /* request before it is terminated by a built-in watchdog timer.
160 /* .IP "\fBipc_timeout (3600s)\fR"
161 /* The time limit for sending or receiving information over an internal
162 /* communication channel.
163 /* .IP "\fBmax_idle (100s)\fR"
164 /* The maximum amount of time that an idle Postfix daemon process waits
165 /* for an incoming connection before terminating voluntarily.
166 /* .IP "\fBmax_use (100)\fR"
167 /* The maximal number of incoming connections that a Postfix daemon
168 /* process will service before terminating voluntarily.
169 /* .IP "\fBprocess_id (read-only)\fR"
170 /* The process ID of a Postfix command or daemon process.
171 /* .IP "\fBprocess_name (read-only)\fR"
172 /* The process name of a Postfix command or daemon process.
173 /* .IP "\fBproxy_read_maps (see 'postconf -d' output)\fR"
174 /* The lookup tables that the \fBproxymap\fR(8) server is allowed to
175 /* access for the read-only service.
176 /* .PP
177 /* Available in Postfix 2.5 and later:
178 /* .IP "\fBdata_directory (see 'postconf -d' output)\fR"
179 /* The directory with Postfix-writable data files (for example:
180 /* caches, pseudo-random numbers).
181 /* .IP "\fBproxy_write_maps (see 'postconf -d' output)\fR"
182 /* The lookup tables that the \fBproxymap\fR(8) server is allowed to
183 /* access for the read-write service.
184 /* .PP
185 /* Available in Postfix 3.3 and later:
186 /* .IP "\fBservice_name (read-only)\fR"
187 /* The master.cf service name of a Postfix daemon process.
188 /* SEE ALSO
189 /* postconf(5), configuration parameters
190 /* master(5), generic daemon options
191 /* README FILES
192 /* .ad
193 /* .fi
194 /* Use "\fBpostconf readme_directory\fR" or
195 /* "\fBpostconf html_directory\fR" to locate this information.
196 /* .na
197 /* .nf
198 /* DATABASE_README, Postfix lookup table overview
199 /* LICENSE
200 /* .ad
201 /* .fi
202 /* The Secure Mailer license must be distributed with this software.
203 /* HISTORY
204 /* .ad
205 /* .fi
206 /* The proxymap service was introduced with Postfix 2.0.
207 /* AUTHOR(S)
208 /* Wietse Venema
209 /* IBM T.J. Watson Research
210 /* P.O. Box 704
211 /* Yorktown Heights, NY 10598, USA
212 /*
213 /* Wietse Venema
214 /* Google, Inc.
215 /* 111 8th Avenue
216 /* New York, NY 10011, USA
217 /*--*/
218 
219 /* System library. */
220 
221 #include <sys_defs.h>
222 #include <string.h>
223 #include <stdlib.h>
224 #include <unistd.h>
225 
226 /* Utility library. */
227 
228 #include <msg.h>
229 #include <mymalloc.h>
230 #include <vstring.h>
231 #include <htable.h>
232 #include <stringops.h>
233 #include <dict.h>
234 
235 /* Global library. */
236 
237 #include <mail_conf.h>
238 #include <mail_params.h>
239 #include <mail_version.h>
240 #include <mail_proto.h>
241 #include <dict_proxy.h>
242 
243 /* Server skeleton. */
244 
245 #include <mail_server.h>
246 
247 /* Application-specific. */
248 
249  /*
250  * XXX All but the last are needed here so that $name expansion dependencies
251  * aren't too broken. The fix is to gather all parameter default settings in
252  * one place.
253  */
272 
273  /*
274  * The pre-approved, pre-parsed list of maps.
275  */
276 static HTABLE *proxy_auth_maps;
277 
278  /*
279  * Shared and static to reduce memory allocation overhead.
280  */
281 static VSTRING *request;
282 static VSTRING *request_map;
283 static VSTRING *request_key;
284 static VSTRING *request_value;
285 static VSTRING *map_type_name_flags;
286 
287  /*
288  * Are we a proxy writer or not?
289  */
290 static int proxy_writer;
291 
292  /*
293  * Silly little macros.
294  */
295 #define STR(x) vstring_str(x)
296 #define VSTREQ(x,y) (strcmp(STR(x),y) == 0)
297 
298 /* proxy_map_find - look up or open table */
299 
300 static DICT *proxy_map_find(const char *map_type_name, int request_flags,
301  int *statp)
302 {
303  DICT *dict;
304 
305 #define PROXY_COLON DICT_TYPE_PROXY ":"
306 #define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
307 #define READ_OPEN_FLAGS O_RDONLY
308 #define WRITE_OPEN_FLAGS (O_RDWR | O_CREAT)
309 
310  /*
311  * Canonicalize the map name. If the map is not on the approved list,
312  * deny the request.
313  */
314 #define PROXY_MAP_FIND_ERROR_RETURN(x) { *statp = (x); return (0); }
315 
316  while (strncmp(map_type_name, PROXY_COLON, PROXY_COLON_LEN) == 0)
317  map_type_name += PROXY_COLON_LEN;
318  /* XXX The following breaks with maps that have ':' in their name. */
319  if (strchr(map_type_name, ':') == 0)
321  if (htable_locate(proxy_auth_maps, map_type_name) == 0) {
322  msg_warn("request for unapproved table: \"%s\"", map_type_name);
323  msg_warn("to approve this table for %s access, list %s:%s in %s:%s",
324  proxy_writer == 0 ? "read-only" : "read-write",
325  DICT_TYPE_PROXY, map_type_name, MAIN_CONF_FILE,
326  proxy_writer == 0 ? VAR_PROXY_READ_MAPS :
329  }
330 
331  /*
332  * Open one instance of a map for each combination of name+flags.
333  *
334  * Assume that a map instance can be shared among clients with different
335  * paranoia flag settings and with different map lookup flag settings.
336  *
337  * XXX The open() flags are passed implicitly, via the selection of the
338  * service name. For a more sophisticated interface, appropriate subsets
339  * of open() flags should be received directly from the client.
340  */
341  vstring_sprintf(map_type_name_flags, "%s:%s", map_type_name,
342  dict_flags_str(request_flags & DICT_FLAG_INST_MASK));
343  if (msg_verbose)
344  msg_info("proxy_map_find: %s", STR(map_type_name_flags));
345  if ((dict = dict_handle(STR(map_type_name_flags))) == 0) {
346  dict = dict_open(map_type_name, proxy_writer ?
348  request_flags);
349  if (dict == 0)
350  msg_panic("proxy_map_find: dict_open null result");
351  dict_register(STR(map_type_name_flags), dict);
352  }
353  dict->error = 0;
354  return (dict);
355 }
356 
357 /* proxymap_sequence_service - remote sequence service */
358 
359 static void proxymap_sequence_service(VSTREAM *client_stream)
360 {
361  int request_flags;
362  DICT *dict;
363  int request_func;
364  const char *reply_key;
365  const char *reply_value;
366  int dict_status;
367  int reply_status;
368 
369  /*
370  * Process the request.
371  */
372  if (attr_scan(client_stream, ATTR_FLAG_STRICT,
373  RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
374  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
375  RECV_ATTR_INT(MAIL_ATTR_FUNC, &request_func),
376  ATTR_TYPE_END) != 3
377  || (request_func != DICT_SEQ_FUN_FIRST
378  && request_func != DICT_SEQ_FUN_NEXT)) {
379  reply_status = PROXY_STAT_BAD;
380  reply_key = reply_value = "";
381  } else if ((dict = proxy_map_find(STR(request_map), request_flags,
382  &reply_status)) == 0) {
383  reply_key = reply_value = "";
384  } else {
385  dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
386  | (request_flags & DICT_FLAG_RQST_MASK));
387  dict_status = dict_seq(dict, request_func, &reply_key, &reply_value);
388  if (dict_status == 0) {
389  reply_status = PROXY_STAT_OK;
390  } else if (dict->error == 0) {
391  reply_status = PROXY_STAT_NOKEY;
392  reply_key = reply_value = "";
393  } else {
394  reply_status = (dict->error == DICT_ERR_RETRY ?
396  reply_key = reply_value = "";
397  }
398  }
399 
400  /*
401  * Respond to the client.
402  */
403  attr_print(client_stream, ATTR_FLAG_NONE,
404  SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
405  SEND_ATTR_STR(MAIL_ATTR_KEY, reply_key),
406  SEND_ATTR_STR(MAIL_ATTR_VALUE, reply_value),
407  ATTR_TYPE_END);
408 }
409 
410 /* proxymap_lookup_service - remote lookup service */
411 
412 static void proxymap_lookup_service(VSTREAM *client_stream)
413 {
414  int request_flags;
415  DICT *dict;
416  const char *reply_value;
417  int reply_status;
418 
419  /*
420  * Process the request.
421  */
422  if (attr_scan(client_stream, ATTR_FLAG_STRICT,
423  RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
424  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
425  RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
426  ATTR_TYPE_END) != 3) {
427  reply_status = PROXY_STAT_BAD;
428  reply_value = "";
429  } else if ((dict = proxy_map_find(STR(request_map), request_flags,
430  &reply_status)) == 0) {
431  reply_value = "";
432  } else if (dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
433  | (request_flags & DICT_FLAG_RQST_MASK)),
434  (reply_value = dict_get(dict, STR(request_key))) != 0) {
435  reply_status = PROXY_STAT_OK;
436  } else if (dict->error == 0) {
437  reply_status = PROXY_STAT_NOKEY;
438  reply_value = "";
439  } else {
440  reply_status = (dict->error == DICT_ERR_RETRY ?
442  reply_value = "";
443  }
444 
445  /*
446  * Respond to the client.
447  */
448  attr_print(client_stream, ATTR_FLAG_NONE,
449  SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
450  SEND_ATTR_STR(MAIL_ATTR_VALUE, reply_value),
451  ATTR_TYPE_END);
452 }
453 
454 /* proxymap_update_service - remote update service */
455 
456 static void proxymap_update_service(VSTREAM *client_stream)
457 {
458  int request_flags;
459  DICT *dict;
460  int dict_status;
461  int reply_status;
462 
463  /*
464  * Process the request.
465  *
466  * XXX We don't close maps, so we must turn on synchronous update to ensure
467  * that the on-disk data is in a consistent state between updates.
468  *
469  * XXX We ignore duplicates, because the proxymap server would abort
470  * otherwise.
471  */
472  if (attr_scan(client_stream, ATTR_FLAG_STRICT,
473  RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
474  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
475  RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
476  RECV_ATTR_STR(MAIL_ATTR_VALUE, request_value),
477  ATTR_TYPE_END) != 4) {
478  reply_status = PROXY_STAT_BAD;
479  } else if (proxy_writer == 0) {
480  msg_warn("refusing %s update request on non-%s service",
481  STR(request_map), MAIL_SERVICE_PROXYWRITE);
482  reply_status = PROXY_STAT_DENY;
483  } else if ((dict = proxy_map_find(STR(request_map), request_flags,
484  &reply_status)) == 0) {
485  /* void */ ;
486  } else {
487  dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
488  | (request_flags & DICT_FLAG_RQST_MASK)
490  dict_status = dict_put(dict, STR(request_key), STR(request_value));
491  if (dict_status == 0) {
492  reply_status = PROXY_STAT_OK;
493  } else if (dict->error == 0) {
494  reply_status = PROXY_STAT_NOKEY;
495  } else {
496  reply_status = (dict->error == DICT_ERR_RETRY ?
498  }
499  }
500 
501  /*
502  * Respond to the client.
503  */
504  attr_print(client_stream, ATTR_FLAG_NONE,
505  SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
506  ATTR_TYPE_END);
507 }
508 
509 /* proxymap_delete_service - remote delete service */
510 
511 static void proxymap_delete_service(VSTREAM *client_stream)
512 {
513  int request_flags;
514  DICT *dict;
515  int dict_status;
516  int reply_status;
517 
518  /*
519  * Process the request.
520  *
521  * XXX We don't close maps, so we must turn on synchronous update to ensure
522  * that the on-disk data is in a consistent state between updates.
523  */
524  if (attr_scan(client_stream, ATTR_FLAG_STRICT,
525  RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
526  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
527  RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
528  ATTR_TYPE_END) != 3) {
529  reply_status = PROXY_STAT_BAD;
530  } else if (proxy_writer == 0) {
531  msg_warn("refusing %s delete request on non-%s service",
532  STR(request_map), MAIL_SERVICE_PROXYWRITE);
533  reply_status = PROXY_STAT_DENY;
534  } else if ((dict = proxy_map_find(STR(request_map), request_flags,
535  &reply_status)) == 0) {
536  /* void */ ;
537  } else {
538  dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
539  | (request_flags & DICT_FLAG_RQST_MASK)
541  dict_status = dict_del(dict, STR(request_key));
542  if (dict_status == 0) {
543  reply_status = PROXY_STAT_OK;
544  } else if (dict->error == 0) {
545  reply_status = PROXY_STAT_NOKEY;
546  } else {
547  reply_status = (dict->error == DICT_ERR_RETRY ?
549  }
550  }
551 
552  /*
553  * Respond to the client.
554  */
555  attr_print(client_stream, ATTR_FLAG_NONE,
556  SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
557  ATTR_TYPE_END);
558 }
559 
560 /* proxymap_open_service - open remote lookup table */
561 
562 static void proxymap_open_service(VSTREAM *client_stream)
563 {
564  int request_flags;
565  DICT *dict;
566  int reply_status;
567  int reply_flags;
568 
569  /*
570  * Process the request.
571  */
572  if (attr_scan(client_stream, ATTR_FLAG_STRICT,
573  RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
574  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
575  ATTR_TYPE_END) != 2) {
576  reply_status = PROXY_STAT_BAD;
577  reply_flags = 0;
578  } else if ((dict = proxy_map_find(STR(request_map), request_flags,
579  &reply_status)) == 0) {
580  reply_flags = 0;
581  } else {
582  reply_status = PROXY_STAT_OK;
583  reply_flags = dict->flags;
584  }
585 
586  /*
587  * Respond to the client.
588  */
589  attr_print(client_stream, ATTR_FLAG_NONE,
590  SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
591  SEND_ATTR_INT(MAIL_ATTR_FLAGS, reply_flags),
592  ATTR_TYPE_END);
593 }
594 
595 /* proxymap_service - perform service for client */
596 
597 static void proxymap_service(VSTREAM *client_stream, char *unused_service,
598  char **argv)
599 {
600 
601  /*
602  * Sanity check. This service takes no command-line arguments.
603  */
604  if (argv[0])
605  msg_fatal("unexpected command-line argument: %s", argv[0]);
606 
607  /*
608  * Deadline enforcement.
609  */
610  if (vstream_fstat(client_stream, VSTREAM_FLAG_DEADLINE) == 0)
611  vstream_control(client_stream,
614 
615  /*
616  * This routine runs whenever a client connects to the socket dedicated
617  * to the proxymap service. All connection-management stuff is handled by
618  * the common code in multi_server.c.
619  */
620  vstream_control(client_stream,
623  if (attr_scan(client_stream,
625  RECV_ATTR_STR(MAIL_ATTR_REQ, request),
626  ATTR_TYPE_END) == 1) {
627  if (VSTREQ(request, PROXY_REQ_LOOKUP)) {
628  proxymap_lookup_service(client_stream);
629  } else if (VSTREQ(request, PROXY_REQ_UPDATE)) {
630  proxymap_update_service(client_stream);
631  } else if (VSTREQ(request, PROXY_REQ_DELETE)) {
632  proxymap_delete_service(client_stream);
633  } else if (VSTREQ(request, PROXY_REQ_SEQUENCE)) {
634  proxymap_sequence_service(client_stream);
635  } else if (VSTREQ(request, PROXY_REQ_OPEN)) {
636  proxymap_open_service(client_stream);
637  } else {
638  msg_warn("unrecognized request: \"%s\", ignored", STR(request));
639  attr_print(client_stream, ATTR_FLAG_NONE,
641  ATTR_TYPE_END);
642  }
643  }
644  vstream_control(client_stream,
647  vstream_fflush(client_stream);
648 }
649 
650 /* dict_proxy_open - intercept remote map request from inside library */
651 
652 DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
653 {
654  if (msg_verbose)
655  msg_info("dict_proxy_open(%s, 0%o, 0%o) called from internal routine",
656  map, open_flags, dict_flags);
657  while (strncmp(map, PROXY_COLON, PROXY_COLON_LEN) == 0)
658  map += PROXY_COLON_LEN;
659  return (dict_open(map, open_flags, dict_flags));
660 }
661 
662 /* post_jail_init - initialization after privilege drop */
663 
664 static void post_jail_init(char *service_name, char **unused_argv)
665 {
666  const char *sep = CHARS_COMMA_SP;
667  const char *parens = CHARS_BRACE;
668  char *saved_filter;
669  char *bp;
670  char *type_name;
671 
672  /*
673  * Are we proxy writer?
674  */
675  if (strcmp(service_name, MAIL_SERVICE_PROXYWRITE) == 0)
676  proxy_writer = 1;
677  else if (strcmp(service_name, MAIL_SERVICE_PROXYMAP) != 0)
678  msg_fatal("service name must be one of %s or %s",
680 
681  /*
682  * Pre-allocate buffers.
683  */
684  request = vstring_alloc(10);
685  request_map = vstring_alloc(10);
686  request_key = vstring_alloc(10);
687  request_value = vstring_alloc(10);
688  map_type_name_flags = vstring_alloc(10);
689 
690  /*
691  * Prepare the pre-approved list of proxied tables.
692  */
693  saved_filter = bp = mystrdup(proxy_writer ? var_proxy_write_maps :
695  proxy_auth_maps = htable_create(13);
696  while ((type_name = mystrtokq(&bp, sep, parens)) != 0) {
697  if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
698  continue;
699  do {
700  type_name += PROXY_COLON_LEN;
701  } while (!strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN));
702  if (strchr(type_name, ':') != 0
703  && htable_locate(proxy_auth_maps, type_name) == 0)
704  (void) htable_enter(proxy_auth_maps, type_name, (void *) 0);
705  }
706  myfree(saved_filter);
707 
708  /*
709  * Never, ever, get killed by a master signal, as that could corrupt a
710  * persistent database when we're in the middle of an update.
711  */
712  if (proxy_writer != 0)
713  setsid();
714 }
715 
716 /* pre_accept - see if tables have changed */
717 
718 static void pre_accept(char *unused_name, char **unused_argv)
719 {
720  const char *table;
721 
722  if (proxy_writer == 0 && (table = dict_changed_name()) != 0) {
723  msg_info("table %s has changed -- restarting", table);
724  exit(0);
725  }
726 }
727 
729 
730 /* main - pass control to the multi-threaded skeleton */
731 
732 int main(int argc, char **argv)
733 {
734  static const CONFIG_STR_TABLE str_table[] = {
751  /* The following two must be last for $mapname to work as expected. */
754  0,
755  };
756 
757  /*
758  * Fingerprint executables and core dumps.
759  */
761 
762  multi_server_main(argc, argv, proxymap_service,
763  CA_MAIL_SERVER_STR_TABLE(str_table),
764  CA_MAIL_SERVER_POST_INIT(post_jail_init),
765  CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
766  /* XXX CA_MAIL_SERVER_SOLITARY if proxywrite */
767  0);
768 }
int msg_verbose
Definition: msg.c:177
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define WRITE_OPEN_FLAGS
#define DEF_TRANSPORT_MAPS
Definition: mail_params.h:485
void myfree(void *ptr)
Definition: mymalloc.c:207
#define VAR_PROXY_WRITE_MAPS
Definition: mail_params.h:2417
#define CA_VSTREAM_CTL_TIMEOUT(v)
Definition: vstream.h:163
HTABLE_INFO * htable_locate(HTABLE *table, const char *key)
Definition: htable.c:242
DICT * dict_proxy_open(const char *map, int open_flags, int dict_flags)
Definition: proxymap.c:652
#define PROXY_COLON
#define CHARS_BRACE
Definition: sys_defs.h:1763
#define DICT_TYPE_PROXY
Definition: dict_proxy.h:22
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define dict_put(dp, key, val)
Definition: dict.h:237
void dict_register(const char *dict_name, DICT *dict_info)
Definition: dict.c:312
#define MAIL_ATTR_FUNC
Definition: mail_proto.h:172
#define DICT_FLAG_RQST_MASK
Definition: dict.h:162
#define DICT_SEQ_FUN_FIRST
Definition: dict.h:200
#define DEF_RELAY_DOMAINS
Definition: mail_params.h:2049
char * var_rcpt_canon_maps
Definition: proxymap.c:264
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define CA_MAIL_SERVER_STR_TABLE(v)
Definition: mail_server.h:57
#define VAR_RELAY_DOMAINS
Definition: mail_params.h:2048
#define DEF_VIRT_ALIAS_DOMS
Definition: mail_params.h:435
#define DICT_SEQ_FUN_NEXT
Definition: dict.h:201
#define PROXY_MAP_FIND_ERROR_RETURN(x)
#define MAIL_ATTR_REQ
Definition: mail_proto.h:124
#define DEF_LOCAL_RCPT_MAPS
Definition: mail_params.h:2357
int flags
Definition: dict.h:81
#define DICT_ERR_RETRY
Definition: dict.h:178
#define MAIL_ATTR_TABLE
Definition: mail_proto.h:152
char * var_transport_maps
Definition: proxymap.c:266
#define READ_OPEN_FLAGS
#define PROXY_REQ_SEQUENCE
Definition: dict_proxy.h:33
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define PROXY_STAT_DENY
Definition: dict_proxy.h:39
MAIL_VERSION_STAMP_DECLARE
Definition: proxymap.c:728
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
DICT * dict_open(const char *, int, int)
Definition: dict_open.c:421
#define VSTREQ(x, y)
Definition: proxymap.c:296
char * var_virt_alias_maps
Definition: proxymap.c:256
#define VAR_RELOCATED_MAPS
Definition: mail_params.h:732
#define VAR_SEND_CANON_MAPS
Definition: mail_params.h:446
Definition: htable.h:25
NORETURN multi_server_main(int, char **, MULTI_SERVER_FN,...)
Definition: multi_server.c:530
char * var_proxy_read_maps
Definition: proxymap.c:270
char * var_virt_mailbox_maps
Definition: proxymap.c:258
#define VAR_VIRT_ALIAS_MAPS
Definition: mail_params.h:430
#define MAIN_CONF_FILE
Definition: mail_params.h:334
#define VAR_VIRT_MAILBOX_DOMS
Definition: mail_params.h:2525
#define VAR_VIRT_ALIAS_DOMS
Definition: mail_params.h:434
#define MAIL_SERVICE_PROXYWRITE
Definition: mail_proto.h:59
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
#define VAR_VIRT_MAILBOX_MAPS
Definition: mail_params.h:2521
Definition: dict.h:78
#define CA_MAIL_SERVER_POST_INIT(v)
Definition: mail_server.h:65
char * var_psc_cache_map
Definition: proxymap.c:269
#define VAR_CANONICAL_MAPS
Definition: mail_params.h:442
#define VAR_TRANSPORT_MAPS
Definition: mail_params.h:484
#define VAR_LOCAL_RCPT_MAPS
Definition: mail_params.h:2356
char * var_verify_map
Definition: proxymap.c:267
#define attr_print
Definition: attr.h:109
#define PROXY_STAT_CONFIG
Definition: dict_proxy.h:40
#define PROXY_REQ_DELETE
Definition: dict_proxy.h:32
#define PROXY_STAT_RETRY
Definition: dict_proxy.h:37
#define DEF_CANONICAL_MAPS
Definition: mail_params.h:443
#define dict_get(dp, key)
Definition: dict.h:236
#define DICT_FLAG_DUP_REPLACE
Definition: dict.h:117
#define PROXY_COLON_LEN
#define DEF_ALIAS_MAPS
Definition: mail_params.h:527
char * var_canonical_maps
Definition: proxymap.c:262
#define CA_VSTREAM_CTL_START_DEADLINE
Definition: vstream.h:171
const char * dict_changed_name(void)
Definition: dict.c:583
#define DEF_VIRT_ALIAS_MAPS
Definition: mail_params.h:431
#define dict_seq(dp, f, key, val)
Definition: dict.h:239
#define PROXY_REQ_UPDATE
Definition: dict_proxy.h:31
#define DEF_SMTPD_SND_AUTH_MAPS
Definition: mail_params.h:1656
#define PROXY_STAT_NOKEY
Definition: dict_proxy.h:36
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
#define PROXY_REQ_OPEN
Definition: dict_proxy.h:29
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
char * var_alias_maps
Definition: proxymap.c:254
char * var_virt_mailbox_doms
Definition: proxymap.c:259
#define VAR_PROXY_READ_MAPS
Definition: mail_params.h:2367
#define DEF_RCPT_CANON_MAPS
Definition: mail_params.h:451
char * var_local_rcpt_maps
Definition: proxymap.c:255
#define MAIL_VERSION_STAMP_ALLOCATE
Definition: mail_version.h:67
#define DEF_PROXY_WRITE_MAPS
Definition: mail_params.h:2418
const char * dict_flags_str(int dict_flags)
Definition: dict.c:647
char * var_send_canon_maps
Definition: proxymap.c:263
#define DICT_FLAG_INST_MASK
Definition: dict.h:166
int error
Definition: dict.h:94
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define VSTREAM_FLAG_DEADLINE
Definition: vstream.h:86
#define DEF_PSC_CACHE_MAP
Definition: mail_params.h:3593
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define DEF_VIRT_MAILBOX_DOMS
Definition: mail_params.h:2526
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
#define VAR_ALIAS_MAPS
Definition: mail_params.h:523
#define DEF_PROXY_READ_MAPS
Definition: mail_params.h:2368
#define VAR_RCPT_CANON_MAPS
Definition: mail_params.h:450
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
char * var_proxy_write_maps
Definition: proxymap.c:271
#define STR(x)
Definition: proxymap.c:295
#define PROXY_STAT_BAD
Definition: dict_proxy.h:38
#define vstream_fstat(vp, fl)
Definition: vstream.h:130
char * var_relocated_maps
Definition: proxymap.c:265
#define PROXY_REQ_LOOKUP
Definition: dict_proxy.h:30
#define MAIL_SERVICE_PROXYMAP
Definition: mail_proto.h:58
char * var_relay_rcpt_maps
Definition: proxymap.c:260
char * var_smtpd_snd_auth_maps
Definition: proxymap.c:268
#define MAIL_ATTR_VALUE
Definition: mail_proto.h:154
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define DICT_FLAG_SYNC_UPDATE
Definition: dict.h:118
#define DEF_VIRT_MAILBOX_MAPS
Definition: mail_params.h:2522
#define VAR_PSC_CACHE_MAP
Definition: mail_params.h:3592
char * var_relay_domains
Definition: proxymap.c:261
#define CA_MAIL_SERVER_PRE_ACCEPT(v)
Definition: mail_server.h:68
#define MAIL_ATTR_KEY
Definition: mail_proto.h:153
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
#define dict_del(dp, key)
Definition: dict.h:238
#define attr_scan
Definition: attr.h:111
#define PROXY_STAT_OK
Definition: dict_proxy.h:35
#define VAR_SMTPD_SND_AUTH_MAPS
Definition: mail_params.h:1655
int main(int argc, char **argv)
Definition: proxymap.c:732
#define ATTR_FLAG_MORE
Definition: attr.h:101
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define DEF_VERIFY_MAP
Definition: mail_params.h:2795
#define DEF_RELAY_RCPT_MAPS
Definition: mail_params.h:2058
#define VAR_VERIFY_MAP
Definition: mail_params.h:2794
char * var_virt_alias_doms
Definition: proxymap.c:257
#define DEF_RELOCATED_MAPS
Definition: mail_params.h:733
#define VAR_RELAY_RCPT_MAPS
Definition: mail_params.h:2057
#define DEF_SEND_CANON_MAPS
Definition: mail_params.h:447
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199