1
0
Fork 0
bind9/bin/named/logconf.c
Daniel Baumann f66ff7eae6
Adding upstream version 1:9.20.9.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 13:32:37 +02:00

372 lines
9.8 KiB
C

/*
* 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/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;
off_t size = 0;
uint64_t maxoffset;
/*
* off_t is a signed integer type, so the maximum
* value is all 1s except for the MSB.
*/
switch (sizeof(off_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 = (off_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);
named_log_setdefaultsslkeylogfile(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;
}