diff options
Diffstat (limited to '')
-rw-r--r-- | bin/named/logconf.c | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/bin/named/logconf.c b/bin/named/logconf.c new file mode 100644 index 0000000..36a19ba --- /dev/null +++ b/bin/named/logconf.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/file.h> +#include <isc/offset.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/stdio.h> +#include <isc/string.h> +#include <isc/syslog.h> +#include <isc/util.h> + +#include <isccfg/cfg.h> +#include <isccfg/log.h> + +#include <named/log.h> +#include <named/logconf.h> + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +/*% + * Set up a logging category according to the named.conf data + * in 'ccat' and add it to 'logconfig'. + */ +static isc_result_t +category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) { + isc_result_t result; + const char *catname; + isc_logcategory_t *category; + isc_logmodule_t *module; + const cfg_obj_t *destinations = NULL; + const cfg_listelt_t *element = NULL; + + catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name")); + category = isc_log_categorybyname(named_g_lctx, catname); + if (category == NULL) { + cfg_obj_log(ccat, named_g_lctx, ISC_LOG_ERROR, + "unknown logging category '%s' ignored", catname); + /* + * Allow further processing by returning success. + */ + return (ISC_R_SUCCESS); + } + + if (logconfig == NULL) { + return (ISC_R_SUCCESS); + } + + module = NULL; + + destinations = cfg_tuple_get(ccat, "destinations"); + for (element = cfg_list_first(destinations); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + const char *channelname = cfg_obj_asstring(channel); + + result = isc_log_usechannel(logconfig, channelname, category, + module); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, CFG_LOGCATEGORY_CONFIG, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "logging channel '%s': %s", channelname, + isc_result_totext(result)); + return (result); + } + } + return (ISC_R_SUCCESS); +} + +/*% + * Set up a logging channel according to the named.conf data + * in 'cchan' and add it to 'logconfig'. + */ +static isc_result_t +channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) { + isc_result_t result = ISC_R_SUCCESS; + isc_logdestination_t dest; + unsigned int type; + unsigned int flags = 0; + int level; + const char *channelname; + const cfg_obj_t *fileobj = NULL; + const cfg_obj_t *syslogobj = NULL; + const cfg_obj_t *nullobj = NULL; + const cfg_obj_t *stderrobj = NULL; + const cfg_obj_t *severity = NULL; + int i; + + channelname = cfg_obj_asstring(cfg_map_getname(channel)); + + (void)cfg_map_get(channel, "file", &fileobj); + (void)cfg_map_get(channel, "syslog", &syslogobj); + (void)cfg_map_get(channel, "null", &nullobj); + (void)cfg_map_get(channel, "stderr", &stderrobj); + + i = 0; + if (fileobj != NULL) { + i++; + } + if (syslogobj != NULL) { + i++; + } + if (nullobj != NULL) { + i++; + } + if (stderrobj != NULL) { + i++; + } + + if (i != 1) { + cfg_obj_log(channel, named_g_lctx, ISC_LOG_ERROR, + "channel '%s': exactly one of file, syslog, " + "null, and stderr must be present", + channelname); + return (ISC_R_FAILURE); + } + + type = ISC_LOG_TONULL; + + if (fileobj != NULL) { + const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file"); + const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size"); + const cfg_obj_t *versionsobj = cfg_tuple_get(fileobj, + "versions"); + const cfg_obj_t *suffixobj = cfg_tuple_get(fileobj, "suffix"); + int32_t versions = ISC_LOG_ROLLNEVER; + isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment; + isc_offset_t size = 0; + uint64_t maxoffset; + + /* + * isc_offset_t is a signed integer type, so the maximum + * value is all 1s except for the MSB. + */ + switch (sizeof(isc_offset_t)) { + case 4: + maxoffset = 0x7fffffffULL; + break; + case 8: + maxoffset = 0x7fffffffffffffffULL; + break; + default: + UNREACHABLE(); + } + + type = ISC_LOG_TOFILE; + + if (versionsobj != NULL && cfg_obj_isuint32(versionsobj)) { + versions = cfg_obj_asuint32(versionsobj); + } else if (versionsobj != NULL && + cfg_obj_isstring(versionsobj) && + strcasecmp(cfg_obj_asstring(versionsobj), + "unlimited") == 0) + { + versions = ISC_LOG_ROLLINFINITE; + } + if (sizeobj != NULL && cfg_obj_isuint64(sizeobj) && + cfg_obj_asuint64(sizeobj) < maxoffset) + { + size = (isc_offset_t)cfg_obj_asuint64(sizeobj); + } + if (suffixobj != NULL && cfg_obj_isstring(suffixobj) && + strcasecmp(cfg_obj_asstring(suffixobj), "timestamp") == 0) + { + suffix = isc_log_rollsuffix_timestamp; + } + + dest.file.stream = NULL; + dest.file.name = cfg_obj_asstring(pathobj); + dest.file.versions = versions; + dest.file.suffix = suffix; + dest.file.maximum_size = size; + } else if (syslogobj != NULL) { + int facility = LOG_DAEMON; + + type = ISC_LOG_TOSYSLOG; + + if (cfg_obj_isstring(syslogobj)) { + const char *facilitystr = cfg_obj_asstring(syslogobj); + (void)isc_syslog_facilityfromstring(facilitystr, + &facility); + } + dest.facility = facility; + } else if (stderrobj != NULL) { + type = ISC_LOG_TOFILEDESC; + dest.file.stream = stderr; + dest.file.name = NULL; + dest.file.versions = ISC_LOG_ROLLNEVER; + dest.file.suffix = isc_log_rollsuffix_increment; + dest.file.maximum_size = 0; + } + + /* + * Munge flags. + */ + { + const cfg_obj_t *printcat = NULL; + const cfg_obj_t *printsev = NULL; + const cfg_obj_t *printtime = NULL; + const cfg_obj_t *buffered = NULL; + + (void)cfg_map_get(channel, "print-category", &printcat); + (void)cfg_map_get(channel, "print-severity", &printsev); + (void)cfg_map_get(channel, "print-time", &printtime); + (void)cfg_map_get(channel, "buffered", &buffered); + + if (printcat != NULL && cfg_obj_asboolean(printcat)) { + flags |= ISC_LOG_PRINTCATEGORY; + } + if (printsev != NULL && cfg_obj_asboolean(printsev)) { + flags |= ISC_LOG_PRINTLEVEL; + } + if (buffered != NULL && cfg_obj_asboolean(buffered)) { + flags |= ISC_LOG_BUFFERED; + } + if (printtime != NULL && cfg_obj_isboolean(printtime)) { + if (cfg_obj_asboolean(printtime)) { + flags |= ISC_LOG_PRINTTIME; + } + } else if (printtime != NULL) { /* local/iso8601/iso8601-utc */ + const char *s = cfg_obj_asstring(printtime); + flags |= ISC_LOG_PRINTTIME; + if (strcasecmp(s, "iso8601") == 0) { + flags |= ISC_LOG_ISO8601; + } else if (strcasecmp(s, "iso8601-utc") == 0) { + flags |= ISC_LOG_ISO8601 | ISC_LOG_UTC; + } + } + } + + level = ISC_LOG_INFO; + if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) { + if (cfg_obj_isstring(severity)) { + const char *str = cfg_obj_asstring(severity); + if (strcasecmp(str, "critical") == 0) { + level = ISC_LOG_CRITICAL; + } else if (strcasecmp(str, "error") == 0) { + level = ISC_LOG_ERROR; + } else if (strcasecmp(str, "warning") == 0) { + level = ISC_LOG_WARNING; + } else if (strcasecmp(str, "notice") == 0) { + level = ISC_LOG_NOTICE; + } else if (strcasecmp(str, "info") == 0) { + level = ISC_LOG_INFO; + } else if (strcasecmp(str, "dynamic") == 0) { + level = ISC_LOG_DYNAMIC; + } + } else { + /* debug */ + level = cfg_obj_asuint32(severity); + } + } + + if (logconfig != NULL) { + isc_log_createchannel(logconfig, channelname, type, level, + &dest, flags); + } + + if (type == ISC_LOG_TOFILE) { + FILE *fp; + + /* + * Test to make sure that file is a plain file. + * Fix defect #22771 + */ + result = isc_file_isplainfile(dest.file.name); + if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) { + /* + * Test that the file can be opened, since + * isc_log_open() can't effectively report + * failures when called in isc_log_doit(). + */ + result = isc_stdio_open(dest.file.name, "a", &fp); + if (result != ISC_R_SUCCESS) { + if (logconfig != NULL && !named_g_nosyslog) { + syslog(LOG_ERR, + "isc_stdio_open '%s' failed: " + "%s", + dest.file.name, + isc_result_totext(result)); + } + } else { + (void)isc_stdio_close(fp); + } + goto done; + } + if (logconfig != NULL && !named_g_nosyslog) { + syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s", + dest.file.name, isc_result_totext(result)); + } + } + +done: + return (result); +} + +isc_result_t +named_logconfig(isc_logconfig_t *logconfig, const cfg_obj_t *logstmt) { + isc_result_t result; + const cfg_obj_t *channels = NULL; + const cfg_obj_t *categories = NULL; + const cfg_listelt_t *element; + bool default_set = false; + bool unmatched_set = false; + const cfg_obj_t *catname; + + if (logconfig != NULL) { + named_log_setdefaultchannels(logconfig); + } + + (void)cfg_map_get(logstmt, "channel", &channels); + for (element = cfg_list_first(channels); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *channel = cfg_listelt_value(element); + CHECK(channel_fromconf(channel, logconfig)); + } + + (void)cfg_map_get(logstmt, "category", &categories); + for (element = cfg_list_first(categories); element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *category = cfg_listelt_value(element); + CHECK(category_fromconf(category, logconfig)); + if (!default_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "default") == 0) { + default_set = true; + } + } + if (!unmatched_set) { + catname = cfg_tuple_get(category, "name"); + if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0) + { + unmatched_set = true; + } + } + } + + if (logconfig != NULL && !default_set) { + CHECK(named_log_setdefaultcategory(logconfig)); + } + + if (logconfig != NULL && !unmatched_set) { + CHECK(named_log_setunmatchedcategory(logconfig)); + } + + return (ISC_R_SUCCESS); + +cleanup: + return (result); +} |