Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / bind-9.3 / bin / named / logconf.c
1 /*
2  * Copyright (C) 2004, 2006  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: logconf.c,v 1.30.2.3.10.4 2006/03/02 00:37:20 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/offset.h>
23 #include <isc/result.h>
24 #include <isc/stdio.h>
25 #include <isc/string.h>
26 #include <isc/syslog.h>
27
28 #include <isccfg/cfg.h>
29 #include <isccfg/log.h>
30
31 #include <named/log.h>
32 #include <named/logconf.h>
33
34 #define CHECK(op) \
35         do { result = (op);                                      \
36                if (result != ISC_R_SUCCESS) goto cleanup;        \
37         } while (0)
38
39 /*
40  * Set up a logging category according to the named.conf data
41  * in 'ccat' and add it to 'lctx'.
42  */
43 static isc_result_t
44 category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *lctx) {
45         isc_result_t result;
46         const char *catname;
47         isc_logcategory_t *category;
48         isc_logmodule_t *module;
49         const cfg_obj_t *destinations = NULL;
50         const cfg_listelt_t *element = NULL;
51
52         catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
53         category = isc_log_categorybyname(ns_g_lctx, catname);
54         if (category == NULL) {
55                 cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
56                             "unknown logging category '%s' ignored",
57                             catname);
58                 /*
59                  * Allow further processing by returning success.
60                  */
61                 return (ISC_R_SUCCESS);
62         }
63
64         module = NULL;
65
66         destinations = cfg_tuple_get(ccat, "destinations");
67         for (element = cfg_list_first(destinations);
68              element != NULL;
69              element = cfg_list_next(element))
70         {
71                 const cfg_obj_t *channel = cfg_listelt_value(element);
72                 const char *channelname = cfg_obj_asstring(channel);
73
74                 result = isc_log_usechannel(lctx, channelname, category,
75                                             module);
76                 if (result != ISC_R_SUCCESS) {
77                         isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
78                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
79                                       "logging channel '%s': %s", channelname,
80                                       isc_result_totext(result));
81                         return (result);
82                 }
83         }
84         return (ISC_R_SUCCESS);
85 }
86
87 /*
88  * Set up a logging channel according to the named.conf data
89  * in 'cchan' and add it to 'lctx'.
90  */
91 static isc_result_t
92 channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *lctx) {
93         isc_result_t result;
94         isc_logdestination_t dest;
95         unsigned int type;
96         unsigned int flags = 0;
97         int level;
98         const char *channelname;
99         const cfg_obj_t *fileobj = NULL;
100         const cfg_obj_t *syslogobj = NULL;
101         const cfg_obj_t *nullobj = NULL;
102         const cfg_obj_t *stderrobj = NULL;
103         const cfg_obj_t *severity = NULL;
104         int i;
105
106         channelname = cfg_obj_asstring(cfg_map_getname(channel));
107
108         (void)cfg_map_get(channel, "file", &fileobj);
109         (void)cfg_map_get(channel, "syslog", &syslogobj);
110         (void)cfg_map_get(channel, "null", &nullobj);
111         (void)cfg_map_get(channel, "stderr", &stderrobj);
112
113         i = 0;
114         if (fileobj != NULL)
115                 i++;
116         if (syslogobj != NULL)
117                 i++;
118         if (nullobj != NULL)
119                 i++;
120         if (stderrobj != NULL)
121                 i++;
122
123         if (i != 1) {
124                 cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
125                               "channel '%s': exactly one of file, syslog, "
126                               "null, and stderr must be present", channelname);
127                 return (ISC_R_FAILURE);
128         }
129
130         type = ISC_LOG_TONULL;
131         
132         if (fileobj != NULL) {
133                 const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
134                 const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
135                 const cfg_obj_t *versionsobj =
136                                  cfg_tuple_get(fileobj, "versions");
137                 isc_int32_t versions = ISC_LOG_ROLLNEVER;
138                 isc_offset_t size = 0;
139
140                 type = ISC_LOG_TOFILE;
141                 
142                 if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
143                         versions = cfg_obj_asuint32(versionsobj);
144                 if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
145                     strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
146                         versions = ISC_LOG_ROLLINFINITE;
147                 if (sizeobj != NULL &&
148                     cfg_obj_isuint64(sizeobj) &&
149                     cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
150                         size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
151                 dest.file.stream = NULL;
152                 dest.file.name = cfg_obj_asstring(pathobj);
153                 dest.file.versions = versions;
154                 dest.file.maximum_size = size;
155         } else if (syslogobj != NULL) {
156                 int facility = LOG_DAEMON;
157
158                 type = ISC_LOG_TOSYSLOG;
159
160                 if (cfg_obj_isstring(syslogobj)) {
161                         const char *facilitystr = cfg_obj_asstring(syslogobj);
162                         (void)isc_syslog_facilityfromstring(facilitystr,
163                                                             &facility);
164                 }
165                 dest.facility = facility;
166         } else if (stderrobj != NULL) {
167                 type = ISC_LOG_TOFILEDESC;
168                 dest.file.stream = stderr;
169                 dest.file.name = NULL;
170                 dest.file.versions = ISC_LOG_ROLLNEVER;
171                 dest.file.maximum_size = 0;
172         }
173
174         /*
175          * Munge flags.
176          */
177         {
178                 const cfg_obj_t *printcat = NULL;
179                 const cfg_obj_t *printsev = NULL;
180                 const cfg_obj_t *printtime = NULL;
181
182                 (void)cfg_map_get(channel, "print-category", &printcat);
183                 (void)cfg_map_get(channel, "print-severity", &printsev);
184                 (void)cfg_map_get(channel, "print-time", &printtime);
185
186                 if (printcat != NULL && cfg_obj_asboolean(printcat))
187                         flags |= ISC_LOG_PRINTCATEGORY;
188                 if (printtime != NULL && cfg_obj_asboolean(printtime))
189                         flags |= ISC_LOG_PRINTTIME;
190                 if (printsev != NULL && cfg_obj_asboolean(printsev))
191                         flags |= ISC_LOG_PRINTLEVEL;
192         }
193
194         level = ISC_LOG_INFO;
195         if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
196                 if (cfg_obj_isstring(severity)) {
197                         const char *str = cfg_obj_asstring(severity);
198                         if (strcasecmp(str, "critical") == 0)
199                                 level = ISC_LOG_CRITICAL;
200                         else if (strcasecmp(str, "error") == 0)
201                                 level = ISC_LOG_ERROR;
202                         else if (strcasecmp(str, "warning") == 0)
203                                 level = ISC_LOG_WARNING;
204                         else if (strcasecmp(str, "notice") == 0)
205                                 level = ISC_LOG_NOTICE;
206                         else if (strcasecmp(str, "info") == 0)
207                                 level = ISC_LOG_INFO;
208                         else if (strcasecmp(str, "dynamic") == 0)
209                                 level = ISC_LOG_DYNAMIC;
210                 } else
211                         /* debug */
212                         level = cfg_obj_asuint32(severity);
213         }
214
215         result = isc_log_createchannel(lctx, channelname,
216                                        type, level, &dest, flags);
217
218         if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
219                 FILE *fp;
220                 
221                 /*
222                  * Test that the file can be opened, since isc_log_open()
223                  * can't effectively report failures when called in
224                  * isc_log_doit().
225                  */
226                 result = isc_stdio_open(dest.file.name, "a", &fp);
227                 if (result != ISC_R_SUCCESS)
228                         isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
229                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
230                                       "logging channel '%s' file '%s': %s",
231                                       channelname, dest.file.name,
232                                       isc_result_totext(result));
233                 else
234                         (void)isc_stdio_close(fp);
235
236                 /*
237                  * Allow named to continue by returning success.
238                  */
239                 result = ISC_R_SUCCESS;
240         }
241
242         return (result);
243 }
244
245 isc_result_t
246 ns_log_configure(isc_logconfig_t *logconf, const cfg_obj_t *logstmt) {
247         isc_result_t result;
248         const cfg_obj_t *channels = NULL;
249         const cfg_obj_t *categories = NULL;
250         const cfg_listelt_t *element;
251         isc_boolean_t default_set = ISC_FALSE;
252         isc_boolean_t unmatched_set = ISC_FALSE;
253         const cfg_obj_t *catname;
254
255         CHECK(ns_log_setdefaultchannels(logconf));
256
257         (void)cfg_map_get(logstmt, "channel", &channels);
258         for (element = cfg_list_first(channels);
259              element != NULL;
260              element = cfg_list_next(element))
261         {
262                 const cfg_obj_t *channel = cfg_listelt_value(element);
263                 CHECK(channel_fromconf(channel, logconf));
264         }
265
266         (void)cfg_map_get(logstmt, "category", &categories);
267         for (element = cfg_list_first(categories);
268              element != NULL;
269              element = cfg_list_next(element))
270         {
271                 const cfg_obj_t *category = cfg_listelt_value(element);
272                 CHECK(category_fromconf(category, logconf));
273                 if (!default_set) {
274                         catname = cfg_tuple_get(category, "name");
275                         if (strcmp(cfg_obj_asstring(catname), "default") == 0)
276                                 default_set = ISC_TRUE;
277                 }
278                 if (!unmatched_set) {
279                         catname = cfg_tuple_get(category, "name");
280                         if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
281                                 unmatched_set = ISC_TRUE;
282                 }
283         }
284
285         if (!default_set)
286                 CHECK(ns_log_setdefaultcategory(logconf));
287
288         if (!unmatched_set)
289                 CHECK(ns_log_setunmatchedcategory(logconf));
290
291         return (ISC_R_SUCCESS);
292
293  cleanup:
294         if (logconf != NULL)
295                 isc_logconfig_destroy(&logconf);
296         return (result);
297 }