7 /* Postfix master - config file access
11 /* void fset_master_ent(path)
14 /* void set_master_ent()
16 /* MASTER_SERV *get_master_ent()
18 /* void end_master_ent()
20 /* void print_master_ent(entry)
21 /* MASTER_SERV *entry;
23 /* void free_master_ent(entry)
24 /* MASTER_SERV *entry;
26 /* This module implements a simple programmatic interface
27 /* for accessing Postfix master process configuration files.
29 /* fset_master_ent() specifies the location of the master process
30 /* configuration file. The pathname is copied.
32 /* set_master_ent() opens the configuration file. It is an error
33 /* to call this routine while the configuration file is still open.
34 /* It is an error to open a configuration file without specifying
35 /* its name to fset_master_ent().
37 /* get_master_ent() reads the next entry from an open configuration
38 /* file and returns the parsed result. A null result means the end
39 /* of file was reached.
41 /* print_master_ent() prints the specified service entry.
43 /* end_master_ent() closes an open configuration file. It is an error
44 /* to call this routine when the configuration file is not open.
46 /* free_master_ent() destroys the memory used for a parsed configuration
49 /* Panics: interface violations. Fatal errors: memory allocation
56 /* The Secure Mailer license must be distributed with this software.
59 /* IBM T.J. Watson Research
61 /* Yorktown Heights, NY 10598, USA
64 /* System libraries. */
67 #include <netinet/in.h>
75 #ifdef STRCASECMP_IN_STRINGS_H
79 /* Utility libraries. */
86 #include <stringops.h>
87 #include <readlline.h>
88 #include <inet_addr_list.h>
89 #include <host_port.h>
90 #include <inet_addr_host.h>
91 #include <sock_addr.h>
95 #include <match_service.h>
96 #include <mail_proto.h>
97 #include <mail_params.h>
98 #include <own_inet_addr.h>
99 #include <wildcard_inet_addr.h>
100 #include <mail_conf.h>
104 #include "master_proto.h"
107 static char *master_path
; /* config file name */
108 static VSTREAM
*master_fp
; /* config file pointer */
109 static int master_line
; /* config file line number */
110 static ARGV
*master_disable
; /* disabled service patterns */
112 static char master_blanks
[] = " \t\r\n";/* field delimiters */
114 static NORETURN
fatal_invalid_field(char *, char *);
115 static NORETURN
fatal_with_context(char *,...);
117 /* fset_master_ent - specify configuration file pathname */
119 void fset_master_ent(char *path
)
121 if (master_path
!= 0)
123 master_path
= mystrdup(path
);
126 /* set_master_ent - open configuration file */
128 void set_master_ent()
130 const char *myname
= "set_master_ent";
133 msg_panic("%s: configuration file still open", myname
);
134 if (master_path
== 0)
135 msg_panic("%s: no configuration file specified", myname
);
136 if ((master_fp
= vstream_fopen(master_path
, O_RDONLY
, 0)) == 0)
137 msg_fatal("open %s: %m", master_path
);
139 if (master_disable
!= 0)
140 msg_panic("%s: service disable list still exists", myname
);
141 master_disable
= match_service_init(var_master_disable
);
144 /* end_master_ent - close configuration file */
146 void end_master_ent()
148 const char *myname
= "end_master_ent";
151 msg_panic("%s: configuration file not open", myname
);
152 if (vstream_fclose(master_fp
) != 0)
153 msg_fatal("%s: close configuration file: %m", myname
);
155 if (master_disable
== 0)
156 msg_panic("%s: no service disable list", myname
);
157 match_service_free(master_disable
);
161 /* fatal_with_context - print fatal error with file/line context */
163 static NORETURN
fatal_with_context(char *format
,...)
165 const char *myname
= "fatal_with_context";
166 VSTRING
*vp
= vstring_alloc(100);
169 if (master_path
== 0)
170 msg_panic("%s: no configuration file specified", myname
);
172 va_start(ap
, format
);
173 vstring_vsprintf(vp
, format
, ap
);
175 msg_fatal("%s: line %d: %s", master_path
, master_line
, vstring_str(vp
));
178 /* fatal_invalid_field - report invalid field value */
180 static NORETURN
fatal_invalid_field(char *name
, char *value
)
182 fatal_with_context("field \"%s\": bad value: \"%s\"", name
, value
);
185 /* get_str_ent - extract string field */
187 static char *get_str_ent(char **bufp
, char *name
, char *def_val
)
191 if ((value
= mystrtok(bufp
, master_blanks
)) == 0)
192 fatal_with_context("missing \"%s\" field", name
);
193 if (strcmp(value
, "-") == 0) {
195 fatal_with_context("field \"%s\" has no default value", name
);
202 /* get_bool_ent - extract boolean field */
204 static int get_bool_ent(char **bufp
, char *name
, char *def_val
)
208 value
= get_str_ent(bufp
, name
, def_val
);
209 if (strcmp("y", value
) == 0) {
211 } else if (strcmp("n", value
) == 0) {
214 fatal_invalid_field(name
, value
);
219 /* get_int_ent - extract integer field */
221 static int get_int_ent(char **bufp
, char *name
, char *def_val
, int min_val
)
226 value
= get_str_ent(bufp
, name
, def_val
);
227 if (!ISDIGIT(*value
) || (n
= atoi(value
)) < min_val
)
228 fatal_invalid_field(name
, value
);
232 /* get_master_ent - read entry from configuration file */
234 MASTER_SERV
*get_master_ent()
236 VSTRING
*buf
= vstring_alloc(100);
237 VSTRING
*junk
= vstring_alloc(100);
245 int unprivileged
; /* passed on to child */
246 int chroot
; /* passed on to child */
251 const char *parse_err
;
252 static char *saved_interfaces
= 0;
255 msg_panic("get_master_ent: config file not open");
256 if (master_disable
== 0)
257 msg_panic("get_master_ent: no service disable list");
260 * XXX We cannot change the inet_interfaces setting for a running master
261 * process. Listening sockets are inherited by child processes so that
262 * closing and reopening those sockets in the master does not work.
264 * Another problem is that library routines still cache results that are
265 * based on the old inet_interfaces setting. It is too much trouble to
266 * recompute everything.
268 * In order to keep our data structures consistent we ignore changes in
269 * inet_interfaces settings, and issue a warning instead.
271 if (saved_interfaces
== 0)
272 saved_interfaces
= mystrdup(var_inet_interfaces
);
275 * Skip blank lines and comment lines.
278 if (readlline(buf
, master_fp
, &master_line
) == 0) {
283 bufp
= vstring_str(buf
);
284 if ((cp
= mystrtok(&bufp
, master_blanks
)) == 0)
287 transport
= get_str_ent(&bufp
, "transport type", (char *) 0);
288 vstring_sprintf(junk
, "%s.%s", name
, transport
);
289 } while (match_service_match(master_disable
, vstring_str(junk
)) != 0);
292 * Parse one logical line from the configuration file. Initialize service
293 * structure members in order.
295 serv
= (MASTER_SERV
*) mymalloc(sizeof(MASTER_SERV
));
304 * All servers busy warning timer.
306 serv
->busy_warn_time
= 0;
309 * Service name. Syntax is transport-specific.
311 serv
->ext_name
= mystrdup(name
);
314 * Transport type: inet (wild-card listen or virtual) or unix.
316 #define STR_SAME !strcmp
318 if (STR_SAME(transport
, MASTER_XPORT_NAME_INET
)) {
319 if (!STR_SAME(saved_interfaces
, var_inet_interfaces
)) {
320 msg_warn("service %s: ignoring %s change",
321 serv
->ext_name
, VAR_INET_INTERFACES
);
322 msg_warn("to change %s, stop and start Postfix",
323 VAR_INET_INTERFACES
);
325 serv
->type
= MASTER_SERV_TYPE_INET
;
326 atmp
= mystrdup(name
);
327 if ((parse_err
= host_port(atmp
, &host
, "", &port
, (char *) 0)) != 0)
328 msg_fatal("%s: line %d: %s in \"%s\"",
329 VSTREAM_PATH(master_fp
), master_line
,
332 serv
->flags
|= MASTER_FLAG_INETHOST
;/* host:port */
333 MASTER_INET_ADDRLIST(serv
) = (INET_ADDR_LIST
*)
334 mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv
)));
335 inet_addr_list_init(MASTER_INET_ADDRLIST(serv
));
336 if (inet_addr_host(MASTER_INET_ADDRLIST(serv
), host
) == 0)
337 msg_fatal("%s: line %d: bad hostname or network address: %s",
338 VSTREAM_PATH(master_fp
), master_line
, name
);
339 inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv
));
340 serv
->listen_fd_count
= MASTER_INET_ADDRLIST(serv
)->used
;
342 MASTER_INET_ADDRLIST(serv
) =
343 strcasecmp(saved_interfaces
, INET_INTERFACES_ALL
) ?
344 own_inet_addr_list() : /* virtual */
345 wildcard_inet_addr_list(); /* wild-card */
346 inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv
));
347 serv
->listen_fd_count
= MASTER_INET_ADDRLIST(serv
)->used
;
349 MASTER_INET_PORT(serv
) = mystrdup(port
);
350 for (n
= 0; /* see below */ ; n
++) {
351 if (n
>= MASTER_INET_ADDRLIST(serv
)->used
) {
352 serv
->flags
|= MASTER_FLAG_LOCAL_ONLY
;
355 if (!sock_addr_in_loopback(SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv
)->addrs
+ n
)))
358 } else if (STR_SAME(transport
, MASTER_XPORT_NAME_UNIX
)) {
359 serv
->type
= MASTER_SERV_TYPE_UNIX
;
360 serv
->listen_fd_count
= 1;
361 serv
->flags
|= MASTER_FLAG_LOCAL_ONLY
;
362 } else if (STR_SAME(transport
, MASTER_XPORT_NAME_FIFO
)) {
363 serv
->type
= MASTER_SERV_TYPE_FIFO
;
364 serv
->listen_fd_count
= 1;
365 serv
->flags
|= MASTER_FLAG_LOCAL_ONLY
;
366 #ifdef MASTER_SERV_TYPE_PASS
367 } else if (STR_SAME(transport
, MASTER_XPORT_NAME_PASS
)) {
368 serv
->type
= MASTER_SERV_TYPE_PASS
;
369 serv
->listen_fd_count
= 1;
370 /* If this is a connection screener, remote clients are likely. */
373 fatal_with_context("bad transport type: %s", transport
);
377 * Service class: public or private.
379 private = get_bool_ent(&bufp
, "private", "y");
382 * Derive an internal service name. The name may depend on service
383 * attributes such as privacy.
385 if (serv
->type
== MASTER_SERV_TYPE_INET
) {
386 MAI_HOSTADDR_STR host_addr
;
387 MAI_SERVPORT_STR serv_port
;
388 struct addrinfo
*res0
;
391 fatal_with_context("inet service cannot be private");
394 * Canonicalize endpoint names so that we correctly handle "reload"
395 * requests after someone changes "25" into "smtp" or vice versa.
399 /* Canonicalize numeric host and numeric or symbolic service. */
400 if (hostaddr_to_sockaddr(host
, port
, 0, &res0
) == 0) {
401 SOCKADDR_TO_HOSTADDR(res0
->ai_addr
, res0
->ai_addrlen
,
402 host
? &host_addr
: (MAI_HOSTADDR_STR
*) 0,
404 serv
->name
= (host
? concatenate("[", host_addr
.buf
, "]:",
405 serv_port
.buf
, (char *) 0) :
406 mystrdup(serv_port
.buf
));
409 /* Canonicalize numeric or symbolic service. */
410 else if (hostaddr_to_sockaddr((char *) 0, port
, 0, &res0
) == 0) {
411 SOCKADDR_TO_HOSTADDR(res0
->ai_addr
, res0
->ai_addrlen
,
412 (MAI_HOSTADDR_STR
*) 0, &serv_port
, 0);
413 serv
->name
= (host
? concatenate("[", host
, "]:",
414 serv_port
.buf
, (char *) 0) :
415 mystrdup(serv_port
.buf
));
418 /* Bad service name? */
420 serv
->name
= mystrdup(name
);
422 } else if (serv
->type
== MASTER_SERV_TYPE_UNIX
) {
423 serv
->name
= mail_pathname(private ? MAIL_CLASS_PRIVATE
:
424 MAIL_CLASS_PUBLIC
, name
);
425 } else if (serv
->type
== MASTER_SERV_TYPE_FIFO
) {
426 serv
->name
= mail_pathname(private ? MAIL_CLASS_PRIVATE
:
427 MAIL_CLASS_PUBLIC
, name
);
428 #ifdef MASTER_SERV_TYPE_PASS
429 } else if (serv
->type
== MASTER_SERV_TYPE_PASS
) {
430 serv
->name
= mail_pathname(private ? MAIL_CLASS_PRIVATE
:
431 MAIL_CLASS_PUBLIC
, name
);
434 msg_panic("bad transport type: %d", serv
->type
);
438 * Listen socket(s). XXX We pre-allocate storage because the number of
439 * sockets is frozen anyway once we build the command-line vector below.
441 if (serv
->listen_fd_count
== 0) {
442 msg_fatal("%s: line %d: no valid IP address found: %s",
443 VSTREAM_PATH(master_fp
), master_line
, name
);
445 serv
->listen_fd
= (int *) mymalloc(sizeof(int) * serv
->listen_fd_count
);
446 for (n
= 0; n
< serv
->listen_fd_count
; n
++)
447 serv
->listen_fd
[n
] = -1;
450 * Privilege level. Default is to restrict process privileges to those of
453 unprivileged
= get_bool_ent(&bufp
, "unprivileged", "y");
456 * Chroot. Default is to restrict file system access to the mail queue.
457 * XXX Chroot cannot imply unprivileged service (for example, the pickup
458 * service runs chrooted but needs privileges to open files as the user).
460 chroot
= get_bool_ent(&bufp
, "chroot", "y");
463 * Wakeup timer. XXX should we require that var_proc_limit == 1? Right
464 * now, the only services that have a wakeup timer also happen to be the
465 * services that have at most one running instance: local pickup and
468 serv
->wakeup_time
= get_int_ent(&bufp
, "wakeup_time", "0", 0);
471 * Find out if the wakeup time is conditional, i.e., wakeup triggers
472 * should not be sent until the service has actually been used.
474 if (serv
->wakeup_time
> 0 && bufp
[*bufp
? -2 : -1] == '?')
475 serv
->flags
|= MASTER_FLAG_CONDWAKE
;
478 * Concurrency limit. Zero means no limit.
480 vstring_sprintf(junk
, "%d", var_proc_limit
);
481 serv
->max_proc
= get_int_ent(&bufp
, "max_proc", vstring_str(junk
), 0);
486 command
= get_str_ent(&bufp
, "command", (char *) 0);
487 serv
->path
= concatenate(var_daemon_dir
, "/", command
, (char *) 0);
490 * Idle and total process count.
492 serv
->avail_proc
= 0;
493 serv
->total_proc
= 0;
496 * Backoff time in case a service is broken.
498 serv
->throttle_delay
= var_throttle_time
;
501 * Shared channel for child status updates.
503 serv
->status_fd
[0] = serv
->status_fd
[1] = -1;
506 * Child process structures.
511 * Command-line vector. Add "-n service_name" when the process name
512 * basename differs from the service name. Always add the transport.
514 serv
->args
= argv_alloc(0);
515 argv_add(serv
->args
, command
, (char *) 0);
516 if (serv
->max_proc
== 1)
517 argv_add(serv
->args
, "-l", (char *) 0);
518 if (serv
->max_proc
== 0)
519 argv_add(serv
->args
, "-z", (char *) 0);
520 if (strcmp(basename(command
), name
) != 0)
521 argv_add(serv
->args
, "-n", name
, (char *) 0);
522 argv_add(serv
->args
, "-t", transport
, (char *) 0);
523 if (master_detach
== 0)
524 argv_add(serv
->args
, "-d", (char *) 0);
526 argv_add(serv
->args
, "-v", (char *) 0);
528 argv_add(serv
->args
, "-u", (char *) 0);
530 argv_add(serv
->args
, "-c", (char *) 0);
531 if ((serv
->flags
& MASTER_FLAG_LOCAL_ONLY
) == 0) {
532 argv_add(serv
->args
, "-o", "stress=" CONFIG_BOOL_YES
, (char *) 0);
533 serv
->stress_param_val
=
534 serv
->args
->argv
[serv
->args
->argc
- 1] + sizeof("stress=") - 1;
535 serv
->stress_param_val
[0] = 0;
537 serv
->stress_param_val
= 0;
538 serv
->stress_expire_time
= 0;
539 if (serv
->listen_fd_count
> 1)
540 argv_add(serv
->args
, "-s",
541 vstring_str(vstring_sprintf(junk
, "%d", serv
->listen_fd_count
)),
543 while ((cp
= mystrtok(&bufp
, master_blanks
)) != 0)
544 argv_add(serv
->args
, cp
, (char *) 0);
545 argv_terminate(serv
->args
);
555 /* print_master_ent - show service entry contents */
557 void print_master_ent(MASTER_SERV
*serv
)
561 msg_info("====start service entry");
562 msg_info("flags: %d", serv
->flags
);
563 msg_info("name: %s", serv
->name
);
565 serv
->type
== MASTER_SERV_TYPE_UNIX
? MASTER_XPORT_NAME_UNIX
:
566 serv
->type
== MASTER_SERV_TYPE_FIFO
? MASTER_XPORT_NAME_FIFO
:
567 serv
->type
== MASTER_SERV_TYPE_INET
? MASTER_XPORT_NAME_INET
:
568 #ifdef MASTER_SERV_TYPE_PASS
569 serv
->type
== MASTER_SERV_TYPE_PASS
? MASTER_XPORT_NAME_PASS
:
571 "unknown transport type");
572 msg_info("listen_fd_count: %d", serv
->listen_fd_count
);
573 msg_info("wakeup: %d", serv
->wakeup_time
);
574 msg_info("max_proc: %d", serv
->max_proc
);
575 msg_info("path: %s", serv
->path
);
576 for (cpp
= serv
->args
->argv
; *cpp
; cpp
++)
577 msg_info("arg[%d]: %s", (int) (cpp
- serv
->args
->argv
), *cpp
);
578 msg_info("avail_proc: %d", serv
->avail_proc
);
579 msg_info("total_proc: %d", serv
->total_proc
);
580 msg_info("throttle_delay: %d", serv
->throttle_delay
);
581 msg_info("status_fd %d %d", serv
->status_fd
[0], serv
->status_fd
[1]);
582 msg_info("children: 0x%lx", (long) serv
->children
);
583 msg_info("next: 0x%lx", (long) serv
->next
);
584 msg_info("====end service entry");
587 /* free_master_ent - destroy process entry */
589 void free_master_ent(MASTER_SERV
*serv
)
593 * Undo what get_master_ent() created.
595 if (serv
->flags
& MASTER_FLAG_INETHOST
) {
596 inet_addr_list_free(MASTER_INET_ADDRLIST(serv
));
597 myfree((char *) MASTER_INET_ADDRLIST(serv
));
599 if (serv
->type
== MASTER_SERV_TYPE_INET
)
600 myfree(MASTER_INET_PORT(serv
));
601 myfree(serv
->ext_name
);
604 argv_free(serv
->args
);
605 myfree((char *) serv
->listen_fd
);
606 myfree((char *) serv
);