1 /* $NetBSD: proxymap.c,v 1.1.1.2 2010/06/17 18:06:59 tron Exp $ */ 2 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). 79 /* 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. 103 /* 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. 107 /* 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. 112 /* 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. 116 /* 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. 127 /* 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. 143 /* 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 /*--*/ 204 205 /* System library. */ 206 207 #include <sys_defs.h> 208 #include <string.h> 209 #include <stdlib.h> 210 #include <unistd.h> 211 212 /* Utility library. */ 213 214 #include <msg.h> 215 #include <mymalloc.h> 216 #include <vstring.h> 217 #include <htable.h> 218 #include <stringops.h> 219 #include <dict.h> 220 221 /* Global library. */ 222 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> 228 229 /* Server skeleton. */ 230 231 #include <mail_server.h> 232 233 /* Application-specific. */ 234 235 /* 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. 239 */ 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; 254 255 /* 256 * The pre-approved, pre-parsed list of maps. 257 */ 258 static HTABLE *proxy_auth_maps; 259 260 /* 261 * Shared and static to reduce memory allocation overhead. 262 */ 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; 268 269 /* 270 * Are we a proxy writer or not? 271 */ 272 static int proxy_writer; 273 274 /* 275 * Silly little macros. 276 */ 277 #define STR(x) vstring_str(x) 278 #define VSTREQ(x,y) (strcmp(STR(x),y) == 0) 279 280 /* proxy_map_find - look up or open table */ 281 282 static DICT *proxy_map_find(const char *map_type_name, int request_flags, 283 int *statp) 284 { 285 DICT *dict; 286 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) 291 292 /* 293 * Canonicalize the map name. If the map is not on the approved list, 294 * deny the request. 295 */ 296 #define PROXY_MAP_FIND_ERROR_RETURN(x) { *statp = (x); return (0); } 297 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); 310 } 311 312 /* 313 * Open one instance of a map for each combination of name+flags. 314 * 315 * Assume that a map instance can be shared among clients with different 316 * paranoia flag settings and with different map lookup flag settings. 317 * 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. 321 */ 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); 332 } 333 334 /* proxymap_lookup_service - remote lookup service */ 335 336 static void proxymap_lookup_service(VSTREAM *client_stream) 337 { 338 int request_flags; 339 DICT *dict; 340 const char *reply_value; 341 int reply_status; 342 343 /* 344 * Process the request. 345 */ 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 = ""; 366 } 367 368 /* 369 * Respond to the client. 370 */ 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); 375 } 376 377 /* proxymap_update_service - remote update service */ 378 379 static void proxymap_update_service(VSTREAM *client_stream) 380 { 381 int request_flags; 382 DICT *dict; 383 int reply_status; 384 385 /* 386 * Process the request. 387 * 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. 390 * 391 * XXX We ignore duplicates, because the proxymap server would abort 392 * otherwise. 393 */ 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; 414 } 415 416 /* 417 * Respond to the client. 418 */ 419 attr_print(client_stream, ATTR_FLAG_NONE, 420 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status, 421 ATTR_TYPE_END); 422 } 423 424 /* proxymap_delete_service - remote delete service */ 425 426 static void proxymap_delete_service(VSTREAM *client_stream) 427 { 428 int request_flags; 429 DICT *dict; 430 int reply_status; 431 432 /* 433 * Process the request. 434 * 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. 437 */ 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; 457 } 458 459 /* 460 * Respond to the client. 461 */ 462 attr_print(client_stream, ATTR_FLAG_NONE, 463 ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status, 464 ATTR_TYPE_END); 465 } 466 467 /* proxymap_open_service - open remote lookup table */ 468 469 static void proxymap_open_service(VSTREAM *client_stream) 470 { 471 int request_flags; 472 DICT *dict; 473 int reply_status; 474 int reply_flags; 475 476 /* 477 * Process the request. 478 */ 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; 491 } 492 493 /* 494 * Respond to the client. 495 */ 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); 500 } 501 502 /* proxymap_service - perform service for client */ 503 504 static void proxymap_service(VSTREAM *client_stream, char *unused_service, 505 char **argv) 506 { 507 508 /* 509 * Sanity check. This service takes no command-line arguments. 510 */ 511 if (argv[0]) 512 msg_fatal("unexpected command-line argument: %s", argv[0]); 513 514 /* 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. 518 */ 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); 536 } 537 } 538 vstream_fflush(client_stream); 539 } 540 541 /* dict_proxy_open - intercept remote map request from inside library */ 542 543 DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) 544 { 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)); 551 } 552 553 /* post_jail_init - initialization after privilege drop */ 554 555 static void post_jail_init(char *service_name, char **unused_argv) 556 { 557 const char *sep = ", \t\r\n"; 558 char *saved_filter; 559 char *bp; 560 char *type_name; 561 562 /* 563 * Are we proxy writer? 564 */ 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); 570 571 /* 572 * Pre-allocate buffers. 573 */ 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); 579 580 /* 581 * Prepare the pre-approved list of proxied tables. 582 */ 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); 595 } 596 myfree(saved_filter); 597 598 /* 599 * Never, ever, get killed by a master signal, as that could corrupt a 600 * persistent database when we're in the middle of an update. 601 */ 602 if (proxy_writer != 0) 603 setsid(); 604 } 605 606 /* pre_accept - see if tables have changed */ 607 608 static void pre_accept(char *unused_name, char **unused_argv) 609 { 610 const char *table; 611 612 if (proxy_writer == 0 && (table = dict_changed_name()) != 0) { 613 msg_info("table %s has changed -- restarting", table); 614 exit(0); 615 } 616 } 617 618 MAIL_VERSION_STAMP_DECLARE; 619 620 /* main - pass control to the multi-threaded skeleton */ 621 622 int main(int argc, char **argv) 623 { 624 static const CONFIG_STR_TABLE str_table[] = { 625 VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0, 626 VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0, 627 VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0, 628 VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0, 629 VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0, 630 VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0, 631 VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, 632 VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0, 633 VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0, 634 VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0, 635 VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0, 636 VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0, 637 VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0, 638 VAR_PROXY_WRITE_MAPS, DEF_PROXY_WRITE_MAPS, &var_proxy_write_maps, 0, 0, 639 0, 640 }; 641 642 /* 643 * Fingerprint executables and core dumps. 644 */ 645 MAIL_VERSION_STAMP_ALLOCATE; 646 647 multi_server_main(argc, argv, proxymap_service, 648 MAIL_SERVER_STR_TABLE, str_table, 649 MAIL_SERVER_POST_INIT, post_jail_init, 650 MAIL_SERVER_PRE_ACCEPT, pre_accept, 651 /* XXX MAIL_SERVER_SOLITARY if proxywrite */ 652 0); 653 } 654