/* $NetBSD: mail_conf.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */
/*++
/* NAME
/* mail_conf 3
/* SUMMARY
/* global configuration parameter management
/* SYNOPSIS
/* #include <mail_conf.h>
/*
/* void mail_conf_read()
/*
/* void mail_conf_suck()
/*
/* void mail_conf_flush()
/*
/* void mail_conf_update(name, value)
/* const char *name;
/* const char *value;
/*
/* const char *mail_conf_lookup(name)
/* const char *name;
/*
/* const char *mail_conf_eval(string)
/* const char *string;
/*
/* const char *mail_conf_eval_once(string)
/* const char *string;
/*
/* const char *mail_conf_lookup_eval(name)
/* const char *name;
/* DESCRIPTION
/* mail_conf_suck() reads the global Postfix configuration file, and
/* stores its values into a global configuration dictionary.
/*
/* mail_conf_read() invokes mail_conf_suck() and assigns the values
/* to global variables by calling mail_params_init().
/*
/* mail_conf_flush() discards the global configuration dictionary.
/* This is needed in programs that read main.cf multiple times, to
/* ensure that deleted parameter settings are handled properly.
/*
/* The following routines are wrappers around the generic dictionary
/* access routines.
/*
/* mail_conf_update() updates the named global parameter. This has
/* no effect on parameters whose value has already been looked up.
/* The update succeeds or the program terminates with fatal error.
/*
/* mail_conf_lookup() looks up the value of the named parameter.
/* A null pointer result means the parameter was not found.
/* The result is volatile and should be copied if it is to be
/* used for any appreciable amount of time.
/*
/* mail_conf_eval() recursively expands any $parameters in the
/* string argument. The result is volatile and should be copied
/* if it is to be used for any appreciable amount of time.
/*
/* mail_conf_eval_once() non-recursively expands any $parameters
/* in the string argument. The result is volatile and should
/* be copied if it is to be used for any appreciable amount
/* of time.
/*
/* mail_conf_lookup_eval() looks up the named parameter, and expands any
/* $parameters in the result. The result is volatile and should be
/* copied if it is to be used for any appreciable amount of time.
/* DIAGNOSTICS
/* Fatal errors: malformed numerical value.
/* ENVIRONMENT
/* MAIL_CONFIG, non-default configuration database
/* MAIL_VERBOSE, enable verbose mode
/* FILES
/* /etc/postfix: default Postfix configuration directory.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* mail_conf_int(3) integer-valued parameters
/* mail_conf_str(3) string-valued parameters
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <vstream.h>
#include <vstring.h>
#include <dict.h>
#include <safe.h>
#include <stringops.h>
#include <readlline.h>
/* Global library. */
#include "mail_params.h"
#include "mail_conf.h"
/* mail_conf_checkdir - authorize non-default directory */
static void mail_conf_checkdir(const char *config_dir)
{
VSTRING *buf;
VSTREAM *fp;
char *path;
char *name;
char *value;
char *cp;
int found = 0;
/*
* If running set-[ug]id, require that a non-default configuration
* directory name is blessed as a bona fide configuration directory in
* the default main.cf file.
*/
path = concatenate(DEF_CONFIG_DIR, "/", "main.cf", (char *) 0);
if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
msg_fatal("open file %s: %m", path);
buf = vstring_alloc(1);
while (found == 0 && readlline(buf, fp, (int *) 0)) {
if (split_nameval(vstring_str(buf), &name, &value) == 0
&& (strcmp(name, VAR_CONFIG_DIRS) == 0
|| strcmp(name, VAR_MULTI_CONF_DIRS) == 0)) {
while (found == 0 && (cp = mystrtok(&value, CHARS_COMMA_SP)) != 0)
if (strcmp(cp, config_dir) == 0)
found = 1;
}
}
if (vstream_fclose(fp))
msg_fatal("read file %s: %m", path);
vstring_free(buf);
if (found == 0) {
msg_error("untrusted configuration directory name: %s", config_dir);
msg_fatal("specify \"%s = %s\" in %s",
VAR_CONFIG_DIRS, config_dir, path);
}
myfree(path);
}
/* mail_conf_read - read global configuration file */
void mail_conf_read(void)
{
mail_conf_suck();
mail_params_init();
}
/* mail_conf_suck - suck in the global configuration file */
void mail_conf_suck(void)
{
char *config_dir;
char *path;
/*
* Permit references to unknown configuration variable names. We rely on
* a separate configuration checking tool to spot misspelled names and
* other kinds of trouble. Enter the configuration directory into the
* default dictionary.
*/
if (var_config_dir)
myfree(var_config_dir);
if ((config_dir = getenv(CONF_ENV_PATH)) == 0)
config_dir = DEF_CONFIG_DIR;
var_config_dir = mystrdup(config_dir);
set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
/*
* If the configuration directory name comes from a different trust
* domain, require that it is listed in the default main.cf file.
*/
if (strcmp(var_config_dir, DEF_CONFIG_DIR) != 0 /* non-default */
&& safe_getenv(CONF_ENV_PATH) == 0 /* non-default */
&& geteuid() != 0) /* untrusted */
mail_conf_checkdir(var_config_dir);
path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
if (dict_load_file_xt(CONFIG_DICT, path) == 0)
msg_fatal("open %s: %m", path);
myfree(path);
}
/* mail_conf_flush - discard configuration dictionary */
void mail_conf_flush(void)
{
if (dict_handle(CONFIG_DICT) != 0)
dict_unregister(CONFIG_DICT);
}
/* mail_conf_eval - expand macros in string */
const char *mail_conf_eval(const char *string)
{
#define RECURSIVE 1
return (dict_eval(CONFIG_DICT, string, RECURSIVE));
}
/* mail_conf_eval_once - expand one level of macros in string */
const char *mail_conf_eval_once(const char *string)
{
#define NONRECURSIVE 0
return (dict_eval(CONFIG_DICT, string, NONRECURSIVE));
}
/* mail_conf_lookup - lookup named variable */
const char *mail_conf_lookup(const char *name)
{
return (dict_lookup(CONFIG_DICT, name));
}
/* mail_conf_lookup_eval - expand named variable */
const char *mail_conf_lookup_eval(const char *name)
{
const char *value;
#define RECURSIVE 1
if ((value = dict_lookup(CONFIG_DICT, name)) != 0)
value = dict_eval(CONFIG_DICT, value, RECURSIVE);
return (value);
}
/* mail_conf_update - update parameter */
void mail_conf_update(const char *key, const char *value)
{
dict_update(CONFIG_DICT, key, value);
}