/*++ /* NAME /* mail_conf 3 /* SUMMARY /* global configuration parameter management /* SYNOPSIS /* #include /* /* void mail_conf_read() /* /* void mail_conf_suck() /* /* void mail_conf_flush() /* /* void mail_conf_checkdir(config_dir) /* const char *config_dir; /* /* 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. When the configuration directory name is not /* trusted, this function requires that the directory name is /* authorized with the alternate_config_directories setting /* in the default main.cf file. /* /* This function requires that all configuration directory /* override mechanisms set the MAIL_CONFIG environment variable, /* even if the override was specified via the command line. /* This reduces the number of pathways that need to be checked /* for possible security attacks. /* /* 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. /* /* mail_conf_checkdir() verifies that configuration directory /* is authorized through settings in the default main.cf file, /* and terminates the program if it is not. /* /* 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 /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA /*--*/ /* System library. */ #include #include #include #include /* Utility library. */ #include #include #include #include #include #include #include #include /* Global library. */ #include "mail_params.h" #include "mail_conf.h" /* mail_conf_checkdir - authorize non-default directory */ 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("unauthorized configuration directory name: %s", config_dir); msg_fatal("specify \"%s = %s\" or \"%s = %s\" in %s", VAR_CONFIG_DIRS, config_dir, VAR_MULTI_CONF_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; /* * The code below requires that all configuration directory override * mechanisms set the CONF_ENV_PATH environment variable, even if the * override was specified via the command line. This reduces the number * of pathways that need to be checked for possible security attacks. * * Note: this code necessarily runs before cleanenv() can enforce the * import_environment scrubbing policy. */ /* * 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 an untrusted source, * require that it is listed in the default main.cf file. */ if (strcmp(var_config_dir, DEF_CONFIG_DIR) != 0 /* non-default */ && unsafe()) /* untrusted env and cli */ 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); }