All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_linelog.c
Go to the documentation of this file.
1 /*
2  * rlm_linelog.c
3  *
4  * Version: $Id: 76c72157d8fc933c1b4c4ce1190ab0ba5065907c $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2004,2006 The FreeRADIUS server project
21  * Copyright 2004 Alan DeKok <aland@freeradius.org>
22  */
23 
24 RCSID("$Id: 76c72157d8fc933c1b4c4ce1190ab0ba5065907c $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
29 #include <freeradius-devel/exfile.h>
30 
31 #ifdef HAVE_FCNTL_H
32 # include <fcntl.h>
33 #endif
34 
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 
39 #ifdef HAVE_GRP_H
40 # include <grp.h>
41 #endif
42 
43 #ifdef HAVE_SYSLOG_H
44 # include <syslog.h>
45 # ifndef LOG_INFO
46 # define LOG_INFO (0)
47 # endif
48 #endif
49 
50 #include <sys/uio.h>
51 
52 typedef enum {
54  LINELOG_DST_FILE, //!< Log to a file.
55  LINELOG_DST_SYSLOG, //!< Log to syslog.
56  LINELOG_DST_UNIX, //!< Log via Unix socket.
57  LINELOG_DST_UDP, //!< Log via UDP.
58  LINELOG_DST_TCP, //!< Log via TCP.
60 
62  { "file", LINELOG_DST_FILE },
63  { "syslog", LINELOG_DST_SYSLOG },
64  { "unix", LINELOG_DST_UNIX },
65  { "udp", LINELOG_DST_UDP },
66  { "tcp", LINELOG_DST_TCP },
67 
68  { NULL , -1 }
69 };
70 
71 typedef struct linelog_net {
72  fr_ipaddr_t dst_ipaddr; //!< Network server.
73  fr_ipaddr_t src_ipaddr; //!< Send requests from a given src_ipaddr.
74  uint16_t port; //!< Network port.
75  struct timeval timeout; //!< How long to wait for read/write operations.
77 
78 /** linelog module instance
79  */
80 typedef struct linelog_instance_t {
81  char const *name; //!< Module instance name.
82  fr_connection_pool_t *pool; //!< Connection pool instance.
83 
84  char const *delimiter; //!< Line termination string (usually \n).
85  size_t delimiter_len; //!< Length of line termination string.
86 
87  vp_tmpl_t *log_src; //!< Source of log messages.
88 
89  vp_tmpl_t *log_ref; //!< Path to a #CONF_PAIR (to use as the source of
90  ///< log messages).
91 
92  linelog_dst_t log_dst; //!< Logging destination.
93  char const *log_dst_str; //!< Logging destination string.
94 
95  struct {
96  char const *facility; //!< Syslog facility string.
97  char const *severity; //!< Syslog severity string.
98  int priority; //!< Bitwise | of severity and facility.
99  } syslog;
100 
101  struct {
102  char const *name; //!< File to write to.
103  uint32_t permissions; //!< Permissions to use when creating new files.
104  char const *group_str; //!< Group to set on new files.
105  gid_t group; //!< Resolved gid.
106  exfile_t *ef; //!< Exclusive file access handle.
107  bool escape; //!< Do filename escaping, yes / no.
108  xlat_escape_t escape_func; //!< Escape function.
109  } file;
110 
111  struct {
112  char const *path; //!< Where the UNIX socket lives.
113  struct timeval timeout; //!< How long to wait for read/write operations.
114  } unix_sock; // Lowercase unix is a macro on some systems?!
115 
116  linelog_net_t tcp; //!< TCP server.
117  linelog_net_t udp; //!< UDP server.
118 
119  CONF_SECTION *cs; //!< #CONF_SECTION to use as the root for #log_ref lookups.
121 
122 typedef struct linelog_conn {
123  int sockfd; //!< File descriptor associated with socket
125 
126 
127 static const CONF_PARSER file_config[] = {
129  { FR_CONF_OFFSET("permissions", PW_TYPE_INTEGER, linelog_instance_t, file.permissions), .dflt = "0600" },
130  { FR_CONF_OFFSET("group", PW_TYPE_STRING, linelog_instance_t, file.group_str) },
131  { FR_CONF_OFFSET("escape_filenames", PW_TYPE_BOOLEAN, linelog_instance_t, file.escape), .dflt = "no" },
133 };
134 
135 static const CONF_PARSER syslog_config[] = {
136  { FR_CONF_OFFSET("facility", PW_TYPE_STRING, linelog_instance_t, syslog.facility) },
137  { FR_CONF_OFFSET("severity", PW_TYPE_STRING, linelog_instance_t, syslog.severity), .dflt = "info" },
139 };
140 
141 static const CONF_PARSER unix_config[] = {
142  { FR_CONF_OFFSET("filename", PW_TYPE_FILE_INPUT, linelog_instance_t, unix_sock.path) },
144 };
145 
146 static const CONF_PARSER udp_config[] = {
147  { FR_CONF_OFFSET("server", PW_TYPE_COMBO_IP_ADDR, linelog_net_t, dst_ipaddr) },
148  { FR_CONF_OFFSET("port", PW_TYPE_SHORT, linelog_net_t, port) },
149  { FR_CONF_OFFSET("timeout", PW_TYPE_TIMEVAL, linelog_net_t, timeout), .dflt = "1000" },
151 };
152 
153 static const CONF_PARSER tcp_config[] = {
154  { FR_CONF_OFFSET("server", PW_TYPE_COMBO_IP_ADDR, linelog_net_t, dst_ipaddr) },
155  { FR_CONF_OFFSET("port", PW_TYPE_SHORT, linelog_net_t, port) },
156  { FR_CONF_OFFSET("timeout", PW_TYPE_TIMEVAL, linelog_net_t, timeout), .dflt = "1000" },
158 };
159 
160 /*
161  * A mapping of configuration file names to internal variables.
162  *
163  * Note that the string is dynamically allocated, so it MUST
164  * be freed. When the configuration file parse re-reads the string,
165  * it free's the old one, and strdup's the new one, placing the pointer
166  * to the strdup'd string into 'config.string'. This gets around
167  * buffer over-flows.
168  */
169 static const CONF_PARSER module_config[] = {
170  { FR_CONF_OFFSET("destination", PW_TYPE_STRING | PW_TYPE_REQUIRED, linelog_instance_t, log_dst_str) },
171 
172  { FR_CONF_OFFSET("delimiter", PW_TYPE_STRING, linelog_instance_t, delimiter), .dflt = "\n" },
173  { FR_CONF_OFFSET("format", PW_TYPE_TMPL, linelog_instance_t, log_src) },
174  { FR_CONF_OFFSET("reference", PW_TYPE_TMPL, linelog_instance_t, log_ref) },
175 
176  /*
177  * Log destinations
178  */
179  { FR_CONF_POINTER("file", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) file_config },
180  { FR_CONF_POINTER("syslog", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) syslog_config },
181  { FR_CONF_POINTER("unix", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) unix_config },
182  { FR_CONF_OFFSET("tcp", PW_TYPE_SUBSECTION, linelog_instance_t, tcp), .dflt = (void const *) tcp_config },
183  { FR_CONF_OFFSET("udp", PW_TYPE_SUBSECTION, linelog_instance_t, udp), .dflt = (void const *) udp_config },
184 
185  /*
186  * Deprecated config items
187  */
189  { FR_CONF_OFFSET("permissions", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, linelog_instance_t, file.permissions) },
190  { FR_CONF_OFFSET("group", PW_TYPE_STRING | PW_TYPE_DEPRECATED, linelog_instance_t, file.group_str) },
191 
192  { FR_CONF_OFFSET("syslog_facility", PW_TYPE_STRING | PW_TYPE_DEPRECATED, linelog_instance_t, syslog.facility) },
193  { FR_CONF_OFFSET("syslog_severity", PW_TYPE_STRING | PW_TYPE_DEPRECATED, linelog_instance_t, syslog.severity) },
195 };
196 
197 
199 {
200  if (shutdown(conn->sockfd, SHUT_RDWR) < 0) DEBUG3("Shutdown failed: %s", fr_syserror(errno));
201  if (close(conn->sockfd) < 0) DEBUG3("Closing socket failed: %s", fr_syserror(errno));
202 
203  return 0;
204 }
205 
206 static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout)
207 {
208  linelog_instance_t *inst = instance;
209  linelog_conn_t *conn;
210  int sockfd = -1;
211 
212  switch (inst->log_dst) {
213  case LINELOG_DST_UNIX:
214  DEBUG2("rlm_linelog (%s): Opening UNIX socket at \"%s\"", inst->name, inst->unix_sock.path);
215  sockfd = fr_socket_client_unix(inst->unix_sock.path, true);
216  if (sockfd < 0) {
217  ERROR("rlm_linelog (%s): Failed opening UNIX socket: %s", inst->name, fr_strerror());
218  return NULL;
219  }
220  break;
221 
222  case LINELOG_DST_TCP:
223  if (DEBUG_ENABLED2) {
224  char buff[FR_IPADDR_PREFIX_STRLEN]; /* IPv6 + /<d><d><d> */
225 
226  fr_inet_ntop_prefix(buff, sizeof(buff), &inst->tcp.dst_ipaddr);
227 
228  DEBUG2("rlm_linelog (%s): Opening TCP connection to %s:%u", inst->name, buff, inst->tcp.port);
229  }
230 
231  sockfd = fr_socket_client_tcp(NULL, &inst->tcp.dst_ipaddr, inst->tcp.port, true);
232  if (sockfd < 0) {
233  ERROR("rlm_linelog (%s): Failed opening TCP socket: %s", inst->name, fr_strerror());
234  return NULL;
235  }
236  break;
237 
238  case LINELOG_DST_UDP:
239  if (DEBUG_ENABLED2) {
240  char buff[FR_IPADDR_PREFIX_STRLEN]; /* IPv6 + /<d><d><d> */
241 
242  fr_inet_ntop_prefix(buff, sizeof(buff), &inst->udp.dst_ipaddr);
243 
244  DEBUG2("rlm_linelog (%s): Opening UDP connection to %s:%u", inst->name, buff, inst->udp.port);
245  }
246 
247  sockfd = fr_socket_client_udp(NULL, &inst->udp.dst_ipaddr, inst->udp.port, true);
248  if (sockfd < 0) {
249  ERROR("rlm_linelog (%s): Failed opening UDP socket: %s", inst->name, fr_strerror());
250  return NULL;
251  }
252  break;
253 
254  /*
255  * Are not connection oriented destinations
256  */
257  case LINELOG_DST_INVALID:
258  case LINELOG_DST_FILE:
259  case LINELOG_DST_SYSLOG:
260  rad_assert(0);
261  return NULL;
262  }
263 
264  if (errno == EINPROGRESS) {
265  if (FR_TIMEVAL_TO_MS(timeout)) {
266  DEBUG2("rlm_linelog (%s): Waiting for connection to complete...", inst->name);
267  } else {
268  DEBUG2("rlm_linelog (%s): Blocking until connection complete...", inst->name);
269  }
270  if (fr_socket_wait_for_connect(sockfd, timeout) < 0) {
271  ERROR("rlm_linelog (%s): %s", inst->name, fr_strerror());
272  close(sockfd);
273  return NULL;
274  }
275  }
276  DEBUG2("rlm_linelog (%s): Connection successful", inst->name);
277 
278  /*
279  * Set blocking operation as we have no timeout set
280  */
281  if (!FR_TIMEVAL_TO_MS(timeout) && (fr_blocking(sockfd) < 0)) {
282  ERROR("rlm_linelog (%s): Failed setting nonblock flag on fd", inst->name);
283  close(sockfd);
284  return NULL;
285  }
286 
287  conn = talloc_zero(ctx, linelog_conn_t);
288  conn->sockfd = sockfd;
289  talloc_set_destructor(conn, _mod_conn_free);
290 
291  return conn;
292 }
293 
294 static int mod_detach(void *instance)
295 {
296  linelog_instance_t *inst = instance;
297 
299 
300  return 0;
301 }
302 
303 
304 /*
305  * Instantiate the module.
306  */
307 static int mod_instantiate(CONF_SECTION *conf, void *instance)
308 {
309  linelog_instance_t *inst = instance;
310  char prefix[100];
311 
312  /*
313  * Escape filenames only if asked.
314  */
315  if (inst->file.escape) {
316  inst->file.escape_func = rad_filename_escape;
317  } else {
318  inst->file.escape_func = rad_filename_make_safe;
319  }
320 
321  inst->log_dst = fr_str2int(linelog_dst_table, inst->log_dst_str, LINELOG_DST_INVALID);
322  if (inst->log_dst == LINELOG_DST_INVALID) {
323  cf_log_err_cs(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
324  return -1;
325  }
326 
327  if (!inst->log_src && !inst->log_ref) {
328  cf_log_err_cs(conf, "Must specify a log format, or reference");
329  return -1;
330  }
331 
332  inst->name = cf_section_name2(conf);
333  if (!inst->name) inst->name = cf_section_name1(conf);
334 
335  snprintf(prefix, sizeof(prefix), "rlm_linelog (%s)", inst->name);
336 
337  /*
338  * Setup the logging destination
339  */
340  switch (inst->log_dst) {
341  case LINELOG_DST_FILE:
342  {
343  if (!inst->file.name) {
344  cf_log_err_cs(conf, "No value provided for 'filename'");
345  return -1;
346  }
347 
348  inst->file.ef = exfile_init(inst, 64, 30, true);
349  if (!inst->file.ef) {
350  cf_log_err_cs(conf, "Failed creating log file context");
351  return -1;
352  }
353 
354  if (inst->file.group_str) {
355  char *endptr;
356 
357  inst->file.group = strtol(inst->file.group_str, &endptr, 10);
358  if (*endptr != '\0') {
359  if (rad_getgid(inst, &(inst->file.group), inst->file.group_str) < 0) {
360  cf_log_err_cs(conf, "Unable to find system group \"%s\"",
361  inst->file.group_str);
362  return -1;
363  }
364  }
365  }
366  }
367  break;
368 
369  case LINELOG_DST_SYSLOG:
370  {
371  int num;
372 
373 #ifndef HAVE_SYSLOG_H
374  cf_log_err_cs(conf, "Syslog output is not supported on this system");
375  return -1;
376 #else
377  if (inst->syslog.facility) {
378  num = fr_str2int(syslog_facility_table, inst->syslog.facility, -1);
379  if (num < 0) {
380  cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog.facility);
381  return -1;
382  }
383  inst->syslog.priority |= num;
384  }
385 
386  num = fr_str2int(syslog_severity_table, inst->syslog.severity, -1);
387  if (num < 0) {
388  cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog.severity);
389  return -1;
390  }
391  inst->syslog.priority |= num;
392 #endif
393  }
394  break;
395 
396  case LINELOG_DST_UNIX:
397 #ifndef HAVE_SYS_UN_H
398  cf_log_err_cs(conf, "Unix sockets are not supported on this sytem");
399  return -1;
400 #else
402  inst, mod_conn_create, NULL, prefix);
403  if (!inst->pool) return -1;
404 #endif
405  break;
406 
407  case LINELOG_DST_UDP:
409  inst, mod_conn_create, NULL, prefix);
410  if (!inst->pool) return -1;
411  break;
412 
413  case LINELOG_DST_TCP:
415  inst, mod_conn_create, NULL, prefix);
416  if (!inst->pool) return -1;
417  break;
418 
419  case LINELOG_DST_INVALID:
420  rad_assert(0);
421  break;
422  }
423 
424  inst->delimiter_len = talloc_array_length(inst->delimiter) - 1;
425  inst->cs = conf;
426 
427  return 0;
428 }
429 
430 /** Escape unprintable characters
431  *
432  * - Newline is escaped as ``\\n``.
433  * - Return is escaped as ``\\r``.
434  * - All other unprintables are escaped as @verbatim <oct><oct><oct> @endverbatim.
435  *
436  * @param request The current request.
437  * @param out Where to write the escaped string.
438  * @param outlen Length of the output buffer.
439  * @param in String to escape.
440  * @param arg unused.
441  */
442 static size_t linelog_escape_func(UNUSED REQUEST *request, char *out, size_t outlen,
443  char const *in, UNUSED void *arg)
444 {
445  int len = 0;
446 
447  if (outlen == 0) return 0;
448  if (outlen == 1) {
449  *out = '\0';
450  return 0;
451  }
452 
453  while (in[0]) {
454  if (in[0] >= ' ') {
455  if (in[0] == '\\') {
456  if (outlen <= 2) break;
457  outlen--;
458  *out++ = '\\';
459  len++;
460  }
461 
462  outlen--;
463  if (outlen == 1) break;
464  *out++ = *in++;
465  len++;
466  continue;
467  }
468 
469  switch (in[0]) {
470  case '\n':
471  if (outlen <= 2) break;
472  *out++ = '\\';
473  *out++ = 'n';
474  in++;
475  len += 2;
476  break;
477 
478  case '\r':
479  if (outlen <= 2) break;
480  *out++ = '\\';
481  *out++ = 'r';
482  in++;
483  len += 2;
484  break;
485 
486  default:
487  if (outlen <= 4) break;
488  snprintf(out, outlen, "\\%03o", (uint8_t) *in);
489  in++;
490  out += 4;
491  outlen -= 4;
492  len += 4;
493  break;
494  }
495  }
496 
497  *out = '\0';
498  return len;
499 }
500 
501 /** Write a linelog message
502  *
503  * Write a log message to syslog or a flat file.
504  *
505  * @param instance of rlm_linelog.
506  * @param request The current request.
507  * @return
508  * - #RLM_MODULE_NOOP if no message to log.
509  * - #RLM_MODULE_FAIL if we failed writing the message.
510  * - #RLM_MODULE_OK on success.
511  */
512 static rlm_rcode_t mod_do_linelog(void *instance, REQUEST *request) CC_HINT(nonnull);
513 static rlm_rcode_t mod_do_linelog(void *instance, REQUEST *request)
514 {
515  int fd = -1;
516  linelog_conn_t *conn;
517  struct timeval *timeout = NULL;
518 
519  char buff[4096];
520  char *p = buff;
521  linelog_instance_t *inst = instance;
522  char const *value;
523  vp_tmpl_t empty, *vpt = NULL, *vpt_p = NULL;
524  rlm_rcode_t rcode = RLM_MODULE_OK;
525  ssize_t slen;
526 
527  struct iovec vector_s[2];
528  struct iovec *vector = NULL, *vector_p;
529  size_t vector_len;
530  bool with_delim;
531 
532  buff[0] = '.'; /* force to be in current section */
533  buff[1] = '\0';
534  buff[2] = '\0';
535 
536  /*
537  * Expand log_ref to a config path, using the module
538  * configuration section as the root.
539  */
540  if (inst->log_ref) {
541  CONF_ITEM *ci;
542  CONF_PAIR *cp;
543  char const *tmpl_str;
544 
545  if (tmpl_expand(NULL, buff + 1, sizeof(buff) - 1,
546  request, inst->log_ref, linelog_escape_func, NULL) < 0) {
547  return RLM_MODULE_FAIL;
548  }
549 
550  if (buff[1] == '.') p++;
551 
552  /*
553  * Don't go back up.
554  */
555  if (buff[2] == '.') {
556  REDEBUG("Invalid path \"%s\"", p);
557  return RLM_MODULE_FAIL;
558  }
559 
560  ci = cf_reference_item(NULL, inst->cs, p);
561  if (!ci) {
562  RDEBUG2("Path \"%s\" doesn't exist", p);
563  goto default_msg;
564  }
565 
566  if (!cf_item_is_pair(ci)) {
567  REDEBUG("Path \"%s\" resolves to a section (should be a pair)", p);
568  return RLM_MODULE_FAIL;
569  }
570 
571  cp = cf_item_to_pair(ci);
572  tmpl_str = cf_pair_value(cp);
573  if (!tmpl_str || (tmpl_str[0] == '\0')) {
574  RDEBUG2("Path \"%s\" resolves to an empty config pair", p);
575  vpt_p = tmpl_init(&empty, TMPL_TYPE_UNPARSED, "", 0, T_DOUBLE_QUOTED_STRING);
576  goto build_vector;
577  }
578 
579  /*
580  * Alloc a template from the value of the CONF_PAIR
581  * using request as the context (which will hopefully avoid a malloc).
582  */
583  slen = tmpl_afrom_str(request, &vpt, tmpl_str, talloc_array_length(tmpl_str) - 1,
585  if (slen <= 0) {
586  REMARKER(tmpl_str, -slen, fr_strerror());
587  return RLM_MODULE_FAIL;
588  }
589  vpt_p = vpt;
590  } else {
591  default_msg:
592  /*
593  * Use the default format string
594  */
595  if (!inst->log_src) {
596  RDEBUG2("No default message configured");
597  return RLM_MODULE_NOOP;
598  }
599  /*
600  * Use the pre-parsed format template
601  */
602  RDEBUG2("Using default message");
603  vpt_p = inst->log_src;
604  }
605 
606 build_vector:
607  with_delim = (inst->log_dst != LINELOG_DST_SYSLOG) && (inst->delimiter_len > 0);
608 
609  /*
610  * Log all the things!
611  */
612  switch (vpt_p->type) {
613  case TMPL_TYPE_ATTR:
614  case TMPL_TYPE_LIST:
615  {
616  #define VECTOR_INCREMENT 20
617  vp_cursor_t cursor;
618  VALUE_PAIR *vp;
619  int alloced = VECTOR_INCREMENT, i;
620 
621  MEM(vector = talloc_array(request, struct iovec, alloced));
622  for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt_p), i = 0;
623  vp;
624  vp = tmpl_cursor_next(&cursor, vpt_p), i++) {
625  /* need extra for line terminator */
626  if ((with_delim && ((i + 1) >= alloced)) ||
627  (i >= alloced)) {
628  alloced += VECTOR_INCREMENT;
629  MEM(vector = talloc_realloc(request, vector, struct iovec, alloced));
630  }
631 
632  switch (vp->da->type) {
633  case PW_TYPE_OCTETS:
634  case PW_TYPE_STRING:
635  vector[i].iov_base = vp->data.ptr;
636  vector[i].iov_len = vp->vp_length;
637  break;
638 
639  default:
640  p = fr_pair_value_asprint(vector, vp, '\0');
641  vector[i].iov_base = p;
642  vector[i].iov_len = talloc_array_length(p) - 1;
643  break;
644  }
645 
646  /*
647  * Add the line delimiter string
648  */
649  if (with_delim) {
650  i++;
651  memcpy(&vector[i].iov_base, &(inst->delimiter), sizeof(vector[i].iov_base));
652  vector[i].iov_len = inst->delimiter_len;
653  }
654  }
655  vector_p = vector;
656  vector_len = i;
657  }
658  break;
659 
660  /*
661  * Log a single thing.
662  */
663  default:
664  slen = tmpl_expand(&value, buff, sizeof(buff), request, vpt_p, linelog_escape_func, NULL);
665  if (slen < 0) {
666  rcode = RLM_MODULE_FAIL;
667  goto finish;
668  }
669 
670  /* iov_base is not declared as const *sigh* */
671  memcpy(&vector_s[0].iov_base, &value, sizeof(vector_s[0].iov_base));
672  vector_s[0].iov_len = slen;
673 
674  if (!with_delim) {
675  vector_len = 1;
676  } else {
677  memcpy(&vector_s[1].iov_base, &(inst->delimiter), sizeof(vector_s[1].iov_base));
678  vector_s[1].iov_len = inst->delimiter_len;
679  vector_len = 2;
680  }
681 
682  vector_p = &vector_s[0];
683  }
684 
685  if (vector_len == 0) {
686  RDEBUG("No data to write");
687  rcode = RLM_MODULE_NOOP;
688  goto finish;
689  }
690 
691  /*
692  * Reserve a handle, write out the data, close the handle
693  */
694  switch (inst->log_dst) {
695  case LINELOG_DST_FILE:
696  {
697  char path[2048];
698 
699  if (radius_xlat(path, sizeof(path), request, inst->file.name, inst->file.escape_func, NULL) < 0) {
700  return RLM_MODULE_FAIL;
701  }
702 
703  /* check path and eventually create subdirs */
704  p = strrchr(path, '/');
705  if (p) {
706  *p = '\0';
707  if (rad_mkdir(path, 0700, -1, -1) < 0) {
708  RERROR("Failed to create directory %s: %s", path, fr_syserror(errno));
709  rcode = RLM_MODULE_FAIL;
710  goto finish;
711  }
712  *p = '/';
713  }
714 
715  fd = exfile_open(inst->file.ef, path, inst->file.permissions, true);
716  if (fd < 0) {
717  RERROR("Failed to open %s: %s", path, fr_syserror(errno));
718  rcode = RLM_MODULE_FAIL;
719  goto finish;
720  }
721 
722  if (inst->file.group_str && (chown(path, -1, inst->file.group) == -1)) {
723  RWARN("Unable to change system group of \"%s\": %s", path, fr_strerror());
724  }
725 
726  if (writev(fd, vector_p, vector_len) < 0) {
727  RERROR("Failed writing to \"%s\": %s", path, fr_syserror(errno));
728  exfile_close(inst->file.ef, fd);
729 
730  /* Assert on the extra fatal errors */
731  rad_assert((errno != EINVAL) && (errno != EFAULT));
732 
733  return RLM_MODULE_FAIL;
734  }
735 
736  exfile_close(inst->file.ef, fd);
737  }
738  break;
739 
740  case LINELOG_DST_UNIX:
741  if (inst->unix_sock.timeout.tv_sec || inst->unix_sock.timeout.tv_usec) {
742  timeout = &inst->unix_sock.timeout;
743  }
744  goto do_write;
745 
746  case LINELOG_DST_UDP:
747  if (inst->udp.timeout.tv_sec || inst->udp.timeout.tv_usec) timeout = &inst->udp.timeout;
748  goto do_write;
749 
750  case LINELOG_DST_TCP:
751  {
752  int i, num;
753  if (inst->tcp.timeout.tv_sec || inst->tcp.timeout.tv_usec) timeout = &inst->tcp.timeout;
754 
755  do_write:
756  num = fr_connection_pool_state(inst->pool)->num;
757  conn = fr_connection_get(inst->pool);
758  if (!conn) {
759  rcode = RLM_MODULE_FAIL;
760  goto finish;
761  }
762 
763  for (i = num; i >= 0; i--) {
764  ssize_t wrote;
765  char discard[64];
766 
767  wrote = fr_writev(conn->sockfd, vector_p, vector_len, timeout);
768  if (wrote < 0) switch (errno) {
769  /* Errors that indicate we should reconnect */
770  case EDESTADDRREQ:
771  case EPIPE:
772  case EBADF:
773  case ECONNRESET:
774  case ENETDOWN:
775  case ENETUNREACH:
776  case EADDRNOTAVAIL: /* Which is OSX for outbound interface is down? */
777  RWARN("Failed writing to socket: %s. Will reconnect and try again...",
778  fr_syserror(errno));
779  conn = fr_connection_reconnect(inst->pool, conn);
780  if (!conn) {
781  rcode = RLM_MODULE_FAIL;
782  goto done;
783  }
784  continue;
785 
786  /* Assert on the extra fatal errors */
787  case EINVAL:
788  case EFAULT:
789  rad_assert(0);
790  /* FALL-THROUGH */
791 
792  /* Normal errors that just cause the module to fail */
793  default:
794  RERROR("Failed writing to socket: %s", fr_syserror(errno));
795  rcode = RLM_MODULE_FAIL;
796  goto done;
797  }
798  RDEBUG2("Wrote %zi bytes", wrote);
799 
800  /* Drain the receive buffer */
801  while (read(conn->sockfd, discard, sizeof(discard)) > 0);
802  break;
803  }
804  done:
805  fr_connection_release(inst->pool, conn);
806  }
807  break;
808 
809 #ifdef HAVE_SYSLOG_H
810  case LINELOG_DST_SYSLOG:
811  {
812  size_t i;
813 
814  for (i = 0; i < vector_len; i++) {
815  syslog(inst->syslog.priority, "%.*s", (int)vector_p[i].iov_len, (char *)vector_p[i].iov_base);
816  }
817  }
818  break;
819 #endif
820  case LINELOG_DST_INVALID:
821  rad_assert(0);
822  rcode = RLM_MODULE_FAIL;
823  break;
824  }
825 
826 finish:
827  talloc_free(vpt);
828  talloc_free(vector);
829 
830  return rcode;
831 }
832 
833 
834 /*
835  * Externally visible module definition.
836  */
837 extern module_t rlm_linelog;
838 module_t rlm_linelog = {
840  .name = "linelog",
841  .type = RLM_TYPE_HUP_SAFE,
842  .inst_size = sizeof(linelog_instance_t),
843  .config = module_config,
844  .instantiate = mod_instantiate,
845  .detach = mod_detach,
846  .methods = {
854 #ifdef WITH_COA
857 #endif
858  },
859 };
Log via Unix socket.
Definition: rlm_linelog.c:56
5 methods index for preproxy section.
Definition: modules.h:46
vp_tmpl_t * log_src
Source of log messages.
Definition: rlm_linelog.c:87
#define PW_TYPE_FILE_INPUT
File matching value must exist, and must be readable.
Definition: conffile.h:204
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Definition: tmpl.c:1479
static int sockfd
Definition: radclient.c:59
FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair)
Return the value (rhs) type.
Definition: conffile.c:3541
ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, size_t inlen, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def, bool do_escape)
Convert an arbitrary string into a vp_tmpl_t.
Definition: tmpl.c:1022
#define DEBUG3(fmt,...)
Definition: log.h:177
#define RERROR(fmt,...)
Definition: log.h:207
int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition: socket.c:167
Log via TCP.
Definition: rlm_linelog.c:58
Time value (struct timeval), only for config items.
Definition: radius.h:55
Log to a file.
Definition: rlm_linelog.c:54
int sockfd
File descriptor associated with socket.
Definition: rlm_linelog.c:123
int fr_blocking(int fd)
linelog module instance
Definition: rlm_linelog.c:80
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
linelog_net_t udp
UDP server.
Definition: rlm_linelog.c:117
linelog_dst_t log_dst
Logging destination.
Definition: rlm_linelog.c:92
#define RWARN(fmt,...)
Definition: log.h:206
#define MEM(x)
Definition: radiusd.h:396
7 methods index for postauth section.
Definition: modules.h:48
struct linelog_instance_t::@18 file
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
Dictionary attribute.
Definition: tmpl.h:133
#define CC_HINT(_x)
Definition: build.h:71
size_t rad_filename_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escapes the raw string such that it should be safe to use as part of a file path. ...
Definition: util.c:269
int fr_socket_client_unix(char const *path, bool async)
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
Definition: log.h:306
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
Unparsed literal string.
Definition: tmpl.h:131
struct linelog_instance_t::@17 syslog
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
char * fr_inet_ntop_prefix(char out[FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition: inet.c:762
#define PW_TYPE_DEPRECATED
If a matching CONF_PAIR is found, error out with a deprecated message.
Definition: conffile.h:199
static float timeout
Definition: radclient.c:43
#define inst
size_t(* xlat_escape_t)(REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
Definition: xlat.h:36
static FR_NAME_NUMBER const linelog_dst_table[]
Definition: rlm_linelog.c:61
#define RLM_TYPE_HUP_SAFE
Will be restarted on HUP.
Definition: modules.h:79
uint16_t port
Network port.
Definition: rlm_linelog.c:74
int rad_mkdir(char *directory, mode_t mode, uid_t uid, gid_t gid)
Create possibly many directories.
Definition: util.c:90
#define PW_TYPE_SUBSECTION
Definition: conffile.h:188
fr_connection_pool_t * pool
Connection pool instance.
Definition: rlm_linelog.c:82
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
struct linelog_instance_t linelog_instance_t
linelog module instance
char const * cf_pair_value(CONF_PAIR const *pair)
Definition: conffile.c:3506
char * fr_pair_value_asprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
Print one attribute value to a string.
Definition: pair.c:2123
int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
Definition: util.c:1248
Log to syslog.
Definition: rlm_linelog.c:55
#define rad_assert(expr)
Definition: rad_assert.h:38
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
VALUE_PAIR * tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
Initialise a vp_cursor_t to the VALUE_PAIR specified by a vp_tmpl_t.
Definition: tmpl.c:1990
fr_connection_pool_t * module_connection_pool_init(CONF_SECTION *module, void *opaque, fr_connection_create_t c, fr_connection_alive_t a, char const *prefix)
Initialise a module specific connection pool.
Definition: modules.c:1759
static rlm_rcode_t mod_do_linelog(void *instance, REQUEST *request) CC_HINT(nonnull)
Write a linelog message.
Definition: rlm_linelog.c:513
static const CONF_PARSER tcp_config[]
Definition: rlm_linelog.c:153
linelog_dst_t
Definition: rlm_linelog.c:52
char const * name
Module instance name.
Definition: rlm_linelog.c:81
int exfile_open(exfile_t *lf, char const *filename, mode_t permissions, bool append)
Open a new log file, or maybe an existing one.
Definition: exfile.c:142
#define DEBUG2(fmt,...)
Definition: log.h:176
#define PW_TYPE_XLAT
string will be dynamically expanded.
Definition: conffile.h:207
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: conffile.c:181
FR_NAME_NUMBER const syslog_severity_table[]
Syslog severity table.
Definition: log.c:177
struct linelog_net linelog_net_t
static bool done
Definition: radclient.c:53
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
static const CONF_PARSER file_config[]
Definition: rlm_linelog.c:127
Attribute list.
Definition: tmpl.h:135
static const CONF_PARSER unix_config[]
Definition: rlm_linelog.c:141
3 methods index for accounting section.
Definition: modules.h:44
int exfile_close(exfile_t *lf, int fd)
Close the log file.
Definition: exfile.c:356
static size_t linelog_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escape unprintable characters.
Definition: rlm_linelog.c:442
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
static const CONF_PARSER udp_config[]
Definition: rlm_linelog.c:146
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
0 methods index for authenticate section.
Definition: modules.h:41
size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Ensures that a filename cannot walk up the directory structure.
Definition: util.c:175
static int _mod_conn_free(linelog_conn_t *conn)
Definition: rlm_linelog.c:198
bool cf_item_is_pair(CONF_ITEM const *item)
Definition: conffile.c:3928
A truth value.
Definition: radius.h:56
Configuration AVP similar to a VALUE_PAIR.
Definition: conffile.c:82
The current request.
Definition: tmpl.h:113
32 Bit unsigned integer.
Definition: radius.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
ssize_t fr_writev(int fd, struct iovec[], int iovcnt, struct timeval *timeout)
Write out a vector to a file descriptor.
Definition: misc.c:492
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
static rs_t * conf
Definition: radsniff.c:46
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
static const CONF_PARSER module_config[]
Definition: rlm_linelog.c:169
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *, char const *name)
Find a sub-section in a section.
Definition: conffile.c:3708
vp_tmpl_t * log_ref
Path to a CONF_PAIR (to use as the source of log messages).
Definition: rlm_linelog.c:89
size_t delimiter_len
Length of line termination string.
Definition: rlm_linelog.c:85
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
vp_tmpl_t * tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Initialise stack allocated vp_tmpl_t.
Definition: tmpl.c:497
fr_ipaddr_t src_ipaddr
Send requests from a given src_ipaddr.
Definition: rlm_linelog.c:73
Module succeeded without doing anything.
Definition: radiusd.h:96
#define RDEBUG2(fmt,...)
Definition: log.h:244
static char const * prefix
Definition: mainconfig.c:81
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
#define PW_TYPE_FILE_OUTPUT
File matching value must exist, and must be writeable.
Definition: conffile.h:205
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
module_t rlm_linelog
Definition: rlm_linelog.c:838
uint32_t num
Number of connections in the pool.
Definition: connection.h:55
static int mod_detach(void *instance)
Definition: rlm_linelog.c:294
struct linelog_instance_t::@19 unix_sock
void * fr_connection_get(fr_connection_pool_t *pool)
Reserve a connection in the connection pool.
Definition: connection.c:1291
A connection pool.
Definition: connection.c:85
struct timeval timeout
How long to wait for read/write operations.
Definition: rlm_linelog.c:75
Log via UDP.
Definition: rlm_linelog.c:57
fr_ipaddr_t dst_ipaddr
Network server.
Definition: rlm_linelog.c:72
#define REDEBUG(fmt,...)
Definition: log.h:254
linelog_net_t tcp
TCP server.
Definition: rlm_linelog.c:116
6 methods index for postproxy section.
Definition: modules.h:47
2 methods index for preacct section.
Definition: modules.h:43
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: conffile.h:200
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Definition: rlm_linelog.c:307
FR_NAME_NUMBER const syslog_facility_table[]
Syslog facility table.
Definition: log.c:110
8 methods index for recvcoa section.
Definition: modules.h:50
IPv4/6 prefix.
Definition: inet.h:41
exfile_t * exfile_init(TALLOC_CTX *ctx, uint32_t entries, uint32_t idle, bool locking)
Initialize a way for multiple threads to log to one or more files.
Definition: exfile.c:100
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_connection_release(fr_connection_pool_t *pool, void *conn)
Release a connection.
Definition: connection.c:1305
struct linelog_conn linelog_conn_t
#define FR_TIMEVAL_TO_MS(_x)
Definition: conffile.h:235
CONF_SECTION * cs
CONF_SECTION to use as the root for log_ref lookups.
Definition: rlm_linelog.c:119
9 methods index for sendcoa section.
Definition: modules.h:51
char const * delimiter
Line termination string (usually ).
Definition: rlm_linelog.c:84
String of printable characters.
Definition: radius.h:33
#define FR_CONF_POINTER(_n, _t, _p)
Definition: conffile.h:172
int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected UDP socket.
Definition: socket.c:273
#define PW_TYPE_TMPL
CONF_PAIR should be parsed as a template.
Definition: conffile.h:208
PW_TYPE type
Value type.
Definition: dict.h:80
1 methods index for authorize section.
Definition: modules.h:42
VALUE_PAIR * tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
Returns the next VALUE_PAIR specified by vpt.
Definition: tmpl.c:2128
static void * mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout)
Definition: rlm_linelog.c:206
#define RCSID(id)
Definition: build.h:135
fr_connection_pool_state_t const * fr_connection_pool_state(fr_connection_pool_t *pool)
Get the number of connections currently in the pool.
Definition: connection.c:1081
int fr_socket_wait_for_connect(int sockfd, struct timeval const *timeout)
Wait for a socket to be connected, with an optional timeout.
Definition: socket.c:359
char const * log_dst_str
Logging destination string.
Definition: rlm_linelog.c:93
void * fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
Reconnect a suspected inviable connection.
Definition: connection.c:1367
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition: inet.h:71
#define RDEBUG(fmt,...)
Definition: log.h:243
A source or sink of value data.
Definition: tmpl.h:187
#define VECTOR_INCREMENT
#define ERROR(fmt,...)
Definition: log.h:145
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601
void fr_connection_pool_free(fr_connection_pool_t *pool)
Delete a connection pool.
Definition: connection.c:1226
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition: log.h:170
static const CONF_PARSER syslog_config[]
Definition: rlm_linelog.c:135
value_data_t data
Definition: pair.h:133
CONF_ITEM * cf_reference_item(CONF_SECTION const *parentcs, CONF_SECTION *outercs, char const *ptr)
Definition: conffile.c:906