The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
log.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 43a2fa5c1478a22af7386fe691d4a5f177de3ff1 $
19  * @file rlm_unbound/log.c
20  * @brief Provides interface between libunbound and the FreeRADIUS event loop
21  *
22  * @copyright 2019 The FreeRADIUS server project
23  * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  */
25 RCSID("$Id: 43a2fa5c1478a22af7386fe691d4a5f177de3ff1 $")
26 
27 #define LOG_PREFIX "unbound"
28 
29 #include <freeradius-devel/util/syserror.h>
30 #include "log.h"
31 
32 /** Write libunbound output to the server or request log
33  *
34  * @param[in] cookie The current thread.
35  * @param[in] buf Log message from unbound.
36  * @param[in] size Length of log message.
37  */
38 static ssize_t _unbound_log_write(void *cookie, char const *buf, size_t size)
39 {
40  unbound_log_t *u_log = talloc_get_type_abort(cookie, unbound_log_t);
41  request_t *request = u_log->request;
42  size_t len = size;
43 
44  if (len == 0) return len;
45  if (buf[len - 1] == '\n') len--; /* Trim trailing new line */
46 
47  ROPTIONAL(RDEBUG, DEBUG, "%pV", fr_box_strvalue_len(buf, len));
48 
49  return size;
50 }
51 
52 /** Set the debug level for a ub_ctx from the request or global debug level
53  *
54  * @param[in] ub Unbound context to set log level for.
55  * @param[in] lvl To set.
56  * @return
57  * - 0 on success.
58  * - -1 on failure.
59  */
60 static int unbound_log_lvl_set(struct ub_ctx *ub, fr_log_lvl_t lvl)
61 {
62  int ret;
63  int level;
64 
65  switch (lvl) {
66  case L_DBG_LVL_DISABLE:
67  case L_DBG_LVL_OFF:
68  case L_DBG_LVL_1:
69  level = 0;
70  break;
71 
72  case L_DBG_LVL_2:
73  level = 1;
74  break;
75 
76  case L_DBG_LVL_3:
77  level = 2; /* Mid-to-heavy levels of output */
78  break;
79 
80  case L_DBG_LVL_4:
81  level = 3; /* Pretty crazy amounts of output */
82  break;
83 
84  case L_DBG_LVL_MAX:
85  default:
86  level = 4; /* Insane amounts of output including crypts */
87  break;
88  }
89 
90  ret = ub_ctx_debuglevel(ub, level);
91  if (ret != 0) {
92  ERROR("Failed setting unbound log level to %i", level);
93  return -1;
94  }
95 
96  return 0;
97 }
98 
99 /** Switch thread-specific libunbound output to the request log destination(s)
100  *
101  */
102 int unbound_log_to_request(unbound_log_t *u_log, struct ub_ctx *ub, request_t *request)
103 {
104  u_log->request = request;
105  return unbound_log_lvl_set(ub, request->log.lvl);
106 }
107 
108 /** Switch thread-specific libunbound output to the global log
109  *
110  * Must be called before a function that previously called #unbound_log_to_request
111  * yields, or can no longer be certain that the request_t * set in t->request
112  * is still valid.
113  */
114 int unbound_log_to_global(unbound_log_t *u_log, struct ub_ctx *ub)
115 {
116  u_log->request = NULL;
117  return unbound_log_lvl_set(ub, fr_debug_lvl);
118 }
119 
121 {
122  if (u_log->stream) fclose(u_log->stream);
123  return 0;
124 }
125 
126 /** Setup an unbound context for log, and initialise a u_log struct
127  *
128  */
129 int unbound_log_init(TALLOC_CTX *ctx, unbound_log_t **u_log_out, struct ub_ctx *ub)
130 {
131  char *val;
132  unbound_log_t *u_log;
133  int ret;
134 
135  /*
136  * Check if the user tried to configure
137  * a log destination, and disable it
138  * if they did.
139  */
140  ret = ub_ctx_get_option(ub, "use-syslog", &val);
141  if ((ret != 0) || !val) {
142  ERROR("Failed retrieving unbound syslog settings: %s", ub_strerror(ret));
143  return -1;
144  }
145 
146  if (strcmp(val, "yes") == 0) {
147  WARN("Disabling unbound syslog output (use-syslog: %s) > (use-syslog: no)", val);
148 
149  ret = ub_ctx_set_option(ub, "use-syslog:", "no");
150  if (ret != 0) {
151  ERROR("Failed disabling unbound syslog output: %s", ub_strerror(ret));
152  free(val);
153  return -1;
154  }
155  }
156  free(val);
157 
158  ret = ub_ctx_get_option(ub, "logfile", &val);
159  if ((ret != 0) || !val) {
160  ERROR("Failed retrieving unbound logfile settings: %s", ub_strerror(ret));
161  return -1;
162  }
163 
164  if (strcmp(val, "yes") == 0) {
165  WARN("Disabling unbound logfile output (logfile: %s) > (logfile: no)", val);
166 
167  ret = ub_ctx_set_option(ub, "logfile:", "no");
168  if (ret != 0) {
169  ERROR("Failed disabling unbound logfile output: %s", ub_strerror(ret));
170  free(val);
171  return -1;
172  }
173  }
174  free(val);
175 
176  MEM(u_log = talloc_zero(ctx, unbound_log_t));
177 
178  /*
179  * Open a FILE stream, and associate a write
180  * function with it, which then call's
181  * FreeRADIUS' log functions.
182  */
183  u_log->stream = fopencookie(u_log, "w", (cookie_io_functions_t){ .write = _unbound_log_write });
184  if (!u_log->stream) {
185  ERROR("Failed creating log stream for unbound: %s", fr_syserror(errno));
186  talloc_free(u_log);
187  return -1;
188  }
189  talloc_set_destructor(u_log, _unbound_log_free); /* Close stream when log struct is freed */
190  setlinebuf(u_log->stream);
191 
192  ret = ub_ctx_debugout(ub, u_log->stream);
193  if (ret != 0) {
194  ERROR("Failed setting log stream for unbound: %s", ub_strerror(ret));
195  talloc_free(u_log);
196  return -1;
197  }
198 
199  /*
200  * Set the initial log level and destination
201  */
202  ret = unbound_log_to_global(u_log, ub);
203  if (ret < 0) {
204  talloc_free(u_log);
205  return -1;
206  }
207 
208  *u_log_out = u_log;
209 
210  return 0;
211 }
#define RCSID(id)
Definition: build.h:444
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
FILE * fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
Definition: fopencookie.c:99
free(array)
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition: log.h:528
talloc_free(reap)
int fr_debug_lvl
Definition: log.c:42
fr_log_lvl_t
Definition: log.h:67
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
Definition: log.h:72
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition: log.h:70
@ L_DBG_LVL_DISABLE
Don't print messages.
Definition: log.h:68
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition: log.h:71
@ L_DBG_LVL_OFF
No debug messages.
Definition: log.h:69
@ L_DBG_LVL_4
4th highest priority debug messages (-xxxx | -Xxx).
Definition: log.h:73
@ L_DBG_LVL_MAX
Lowest priority debug messages (-xxxxx | -Xxxx).
Definition: log.h:74
long int ssize_t
Definition: merged_model.c:24
int unbound_log_to_global(unbound_log_t *u_log, struct ub_ctx *ub)
Switch thread-specific libunbound output to the global log.
Definition: log.c:114
static ssize_t _unbound_log_write(void *cookie, char const *buf, size_t size)
Write libunbound output to the server or request log.
Definition: log.c:38
static int _unbound_log_free(unbound_log_t *u_log)
Definition: log.c:120
static int unbound_log_lvl_set(struct ub_ctx *ub, fr_log_lvl_t lvl)
Set the debug level for a ub_ctx from the request or global debug level.
Definition: log.c:60
int unbound_log_to_request(unbound_log_t *u_log, struct ub_ctx *ub, request_t *request)
Switch thread-specific libunbound output to the request log destination(s)
Definition: log.c:102
int unbound_log_init(TALLOC_CTX *ctx, unbound_log_t **u_log_out, struct ub_ctx *ub)
Setup an unbound context for log, and initialise a u_log struct.
Definition: log.c:129
Function prototypes and datatypes for the REST (HTTP) transport.
request_t * request
Request we're logging to.
Definition: log.h:45
FILE * stream
Stream we use to interface with the FreeRADIUS logging functions.
Definition: log.h:46
Logging state.
Definition: log.h:44
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define WARN(fmt,...)
Definition: radclient.h:47
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279