The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
radsnmp.c
Go to the documentation of this file.
1 /*
2  * This program 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
5  * (at 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: fb5006af72434597e91bb20cee71ca4a459ac396 $
19  *
20  * @brief SNMP to request utility
21  * @file src/bin/radsnmp.c
22  *
23  * @copyright 2015-2016 The FreeRADIUS server project
24  * @copyright 2015-2016 Network RADIUS SAS (legal@networkradius.com)
25  *
26  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
27  */
28 RCSID("$Id: fb5006af72434597e91bb20cee71ca4a459ac396 $")
29 
30 #include <freeradius-devel/util/conf.h>
31 #include <freeradius-devel/util/udp.h>
32 #include <freeradius-devel/util/syserror.h>
33 #include <freeradius-devel/util/atexit.h>
34 #include <freeradius-devel/radius/radius.h>
35 #include <freeradius-devel/radius/list.h>
36 
37 #include <ctype.h>
38 #include <fcntl.h>
39 #include <sys/uio.h>
40 
41 #ifdef HAVE_GETOPT_H
42 # include <getopt.h>
43 #endif
44 
45 #include <assert.h>
46 
47 static char const *radsnmp_version = RADIUSD_VERSION_BUILD("radsnmp");
48 
49 static bool stop;
50 
51 #undef DEBUG
52 #define DEBUG(fmt, ...) if (fr_debug_lvl >= L_DBG_LVL_1) fr_log(&default_log, L_DBG, __FILE__, __LINE__, "radsnmp (debug): " fmt, ## __VA_ARGS__)
53 #undef DEBUG2
54 #define DEBUG2(fmt, ...) if (fr_debug_lvl >= L_DBG_LVL_2) fr_log(&default_log, L_DBG, __FILE__, __LINE__, "radsnmp (debug): " fmt, ## __VA_ARGS__)
55 
56 #define ERROR(fmt, ...) fr_log(&default_log, L_DBG, __FILE__, __LINE__, "radsnmp (error): " fmt, ## __VA_ARGS__)
57 
58 typedef enum {
59  RADSNMP_UNKNOWN = -1, //!< Unknown command.
60  RADSNMP_PING = 0, //!< Check server is alive.
61  RADSNMP_GET, //!< Get an SNMP leaf value.
62  RADSNMP_GETNEXT, //!< Get next OID.
63  RADSNMP_SET, //!< Set OID.
64  RADSNMP_EXIT //!< Terminate gracefully.
66 
68  { L(""), RADSNMP_EXIT }, //!< Terminate radsnmp.
69  { L("PING"), RADSNMP_PING }, //!< Liveness command from Net-SNMP
70  { L("get"), RADSNMP_GET }, //!< Get the value of an OID.
71  { L("getnext"), RADSNMP_GETNEXT }, //!< Get the next OID in the tree.
72  { L("set"), RADSNMP_SET }, //!< Set the value of an OID.
73 };
75 
76 typedef struct {
77  fr_dict_t *dict; //!< Radius protocol dictionary.
78  fr_dict_attr_t const *snmp_root; //!< SNMP protocol root in the FreeRADIUS dictionary.
79  fr_dict_attr_t const *snmp_oid_root; //!< First attribute to include at the start of OID responses.
80  fr_dict_attr_t const *snmp_op; //!< SNMP operation.
81  fr_dict_attr_t const *snmp_type; //!< SNMP type attribute.
82  fr_dict_attr_t const *snmp_failure; //!< SNMP set error attribute.
83  char const *raddb_dir; //!< Radius dictionary directory.
84  char const *dict_dir; //!< Dictionary director.
85  unsigned int code; //!< Request type.
86  int proto; //!< Protocol TCP/UDP.
87  char const *proto_str; //!< Protocol string.
88  uint8_t last_used_id; //!< ID of the last request we sent.
89 
90  fr_ipaddr_t server_ipaddr; //!< Src IP address.
91  uint16_t server_port; //!< Port to send requests to.
92 
93  unsigned int retries; //!< Number of retries.
95  char *secret; //!< Shared secret.
97 
98 static fr_dict_t const *dict_freeradius;
99 static fr_dict_t const *dict_radius;
100 
103  { .out = &dict_freeradius, .proto = "freeradius" },
104  { .out = &dict_radius, .proto = "radius" },
105  { NULL }
106 };
107 
114 
117  { .out = &attr_extended_attribute_1, .name = "Extended-Attribute-1", .type = FR_TYPE_TLV, .dict = &dict_radius },
118  { .out = &attr_freeradius_snmp_failure, .name = "FreeRADIUS-SNMP-Failure", .type = FR_TYPE_UINT8, .dict = &dict_radius },
119  { .out = &attr_freeradius_snmp_operation, .name = "FreeRADIUS-SNMP-Operation", .type = FR_TYPE_UINT8, .dict = &dict_radius },
120  { .out = &attr_freeradius_snmp_type, .name = "FreeRADIUS-SNMP-Type", .type = FR_TYPE_UINT8, .dict = &dict_radius },
121  { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
122  { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
123  { NULL }
124 };
125 
126 static NEVER_RETURNS void usage(void)
127 {
128  fprintf(stderr, "Usage: radsnmp [options] server[:port] [<secret>]\n");
129 
130  fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
131  fprintf(stderr, " -4 Use IPv4 address of server\n");
132  fprintf(stderr, " -6 Use IPv6 address of server.\n");
133  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
134  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
135  fprintf(stderr, " -h Print usage help information.\n");
136  fprintf(stderr, " -l <file> Log output to file.\n");
137  fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
138  fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
139  fprintf(stderr, " -S <file> read secret from file, not command line.\n");
140  fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating "
141  "point number).\n");
142  fprintf(stderr, " -v Show program version information.\n");
143  fprintf(stderr, " -x Increase debug level.\n");
144 
145  fr_exit_now(EXIT_SUCCESS);
146 }
147 
148 #define RESPOND_STATIC(_cmd) \
149 do {\
150  DEBUG2("said: %s", _cmd);\
151  if (write(STDOUT_FILENO, _cmd "\n", sizeof(_cmd)) < 0) return 1; \
152 } while (0)
153 
154 static void rs_signal_stop(UNUSED int sig)
155 {
156  stop = true;
157 }
158 
159 /** Allocate a new request using values from radsnmp config
160  *
161  * @param conf radsnmp config.
162  * @param fd the request will be sent on.
163  * @return new request.
164  */
166 {
167  fr_packet_t *packet;
168 
169  packet = fr_packet_alloc(conf, true);
170 
171  packet->code = conf->code;
172 
173  packet->id = conf->last_used_id;
174  conf->last_used_id = (conf->last_used_id + 1) & UINT8_MAX;
175 
176  memcpy(&packet->socket.inet.dst_ipaddr, &conf->server_ipaddr, sizeof(packet->socket.inet.dst_ipaddr));
177  packet->socket.inet.dst_port = conf->server_port;
178  packet->socket.fd = fd;
179 
180  return packet;
181 }
182 
183 /** Builds attribute representing OID string and adds 'index' attributes where required
184  *
185  * Will convert an OID string in the format @verbatim .1.2.3.4.5.0 @endverbatim
186  * into a pair with a #fr_dict_attr_t of the dictionary attribute matching the OID
187  * string, as evaluated from the specified parent.
188  *
189  * If an OID component does not match a child of a previous OID component, but a child
190  * with attribute number 0 exists, and a child with attribute number 1 also exists,
191  * the child with attribute number 0 will be used as an 'index' pair, and will be
192  * created with the value of the non matching OID component.
193  *
194  * Parsing will then resume using the child with attribute number 1.
195  *
196  * This allows traversals of SNMP tables to be represented by the sequence of pairs
197  * and allows the full range of entry indexes which would not be possible if we represented
198  * table index numbers as TLV attributes.
199  *
200  * @param[in] ctx to allocate new pairs in.
201  * @param[in] conf radsnmp config.
202  * @param[in] cursor to add pairs to.
203  * @param[in] oid string to evaluate.
204  * @param[in] type SNMP value type.
205  * @param[in] value to assign to OID attribute (SET operations only).
206  * @return
207  * - >0 on success (how much of the OID string we parsed).
208  * - <=0 on failure (where format error occurred).
209  */
211  char const *oid, int type, char const *value)
212 {
213  ssize_t slen;
214  char const *p = oid;
215  unsigned int attr;
216  fr_dict_attr_t const *index_attr, *da;
217  fr_dict_attr_t const *parent = conf->snmp_root;
218  fr_pair_t *vp;
219  int ret;
220 
221  if (!oid) return 0;
222 
223  fr_dcursor_tail(cursor);
224 
225  /*
226  * Trim first.
227  */
228  if (p[0] == '.') p++;
229 
230  /*
231  * Support for indexes. If we can't find an attribute
232  * matching a child at a given level in the OID tree,
233  * look for attribute 0 (type integer) at that level.
234  * We use this to represent the index instead.
235  */
236  for (;;) {
237  unsigned int num = 0;
238 
239  slen = fr_dict_attr_by_oid_legacy(conf->dict, &parent, &attr, p);
240  if (slen > 0) break;
241  p += -(slen);
242 
243  if (fr_dict_oid_component_legacy(&num, &p) < 0) break; /* Just advances the pointer */
244  assert(attr == num);
245  p++;
246 
247  /*
248  * Check for an index attribute
249  */
250  index_attr = fr_dict_attr_child_by_num(parent, 0);
251  if (!index_attr) {
252  fr_strerror_const("Unknown OID component: No index attribute at this level");
253  break;
254  }
255 
256  if (index_attr->type != FR_TYPE_UINT32) {
257  fr_strerror_printf("Index is not a \"integer\"");
258  break;
259  }
260 
261  /*
262  * By convention SNMP entries are at .1
263  */
265  if (!parent) {
266  fr_strerror_const("Unknown OID component: No entry attribute at this level");
267  break;
268  }
269 
270  /*
271  * Entry must be a TLV type
272  */
273  if (parent->type != FR_TYPE_TLV) {
274  fr_strerror_printf("Entry is not \"tlv\"");
275  break;
276  }
277 
278  /*
279  * We've skipped over the index attribute, and
280  * the index number should be available in attr.
281  */
282  MEM(vp = fr_pair_afrom_da(ctx, index_attr));
283  vp->vp_uint32 = attr;
284 
285  fr_dcursor_append(cursor, vp);
286  }
287 
288  /*
289  * We errored out processing the OID.
290  */
291  if (slen <= 0) {
292  error:
293  fr_dcursor_free_list(cursor);
294  return slen;
295  }
296 
297  fr_strerror_clear(); /* Clear pending errors */
298 
299  /*
300  * SNMP requests the leaf under the OID with .0.
301  */
302  if (attr != 0) {
303  da = fr_dict_attr_child_by_num(parent, attr);
304  if (!da) {
305  fr_strerror_printf("Unknown leaf attribute %i", attr);
306  return -(slen);
307  }
308  } else {
309  da = parent;
310  }
311 
312  /*
313  * TLVs are special, they cannot hold values. The caller should know this!
314  */
315  if (da->type == FR_TYPE_TLV) {
316  if (!value) return slen;
317 
318  fr_strerror_const("TLVs cannot hold values");
319  return -(slen);
320  }
321 
322  MEM(vp = fr_pair_afrom_da(ctx, da));
323 
324  /*
325  * fr_pair_ts with no value need a 1 byte value buffer.
326  */
327  if (!value) {
328  switch (vp->vp_type) {
329  case FR_TYPE_OCTETS:
330  fr_pair_value_memdup(vp, (uint8_t const *)"\0", 1, true);
331  break;
332 
333  case FR_TYPE_STRING:
334  fr_pair_value_bstrndup(vp, "\0", 1, true);
335  break;
336 
337  /*
338  * Fine to leave other values zeroed out.
339  */
340  default:
341  break;
342  }
343 
344  fr_dcursor_append(cursor, vp);
345  return slen;
346  }
347 
348  ret = fr_pair_value_from_str(vp, value, strlen(value), NULL, true);
349  if (ret < 0) {
350  slen = -(slen);
351  goto error;
352  }
353 
355  vp->vp_uint32 = type;
356 
357  fr_dcursor_append(cursor, vp);
358 
359  return slen;
360 }
361 
362 /** Write the result of a get or getnext operation back to net-snmp
363  *
364  * Returns three lines of output per attribute:
365  * - OID string
366  * - type
367  * - value
368  *
369  * Index attributes (num 0) must be in order of depth (shallowest first).
370  *
371  * If no attributes were written, will write "NONE\n" to inform net-snmp
372  * that no value was available at the specified OID.
373  *
374  * @param fd to write to.
375  * @param root of the SNMP portion of the main dictionary.
376  * @param type attribute.
377  * @param head of list of attributes to convert and write.
378  * @return
379  * - >=0 on success (the number of varbind responses written).
380  * - -1 on failure.
381  */
382 static int radsnmp_get_response(int fd,
383  fr_dict_attr_t const *root, fr_dict_attr_t const *type,
385 {
386  fr_dcursor_t cursor;
387  fr_pair_t *vp, *type_vp;
388  fr_dict_attr_t const *parent = root;
389  unsigned int written = 0;
390 
391  ssize_t slen;
392  size_t len;
393 
394  char type_buff[32]; /* type */
395  size_t type_len = 0;
396  char oid_buff[256];
397  char value_buff[128];
398  char *p = oid_buff, *end = p + sizeof(oid_buff);
399 
400  struct iovec io_vector[6];
401 
402  char newline[] = "\n";
403 
404  type_buff[0] = '\0';
405 
406  /*
407  * Print first part of OID string.
408  */
409  slen = snprintf(oid_buff, sizeof(oid_buff), "%u.", parent->attr);
410  if (is_truncated((size_t)slen, sizeof(oid_buff))) {
411  oob:
412  fr_strerror_const("OID Buffer too small");
413  return -1;
414  }
415  p += slen;
416 
417  /*
418  * @fixme, this is very dependent on ordering
419  *
420  * This code should be reworked when we have proper
421  * attribute grouping to coalesce all related index
422  * attributes under a single request OID.
423  */
424  for (vp = fr_pair_dcursor_init(&cursor, head);
425  vp;
426  vp = fr_dcursor_next(&cursor)) {
427  fr_dict_attr_t const *common;
428  fr_value_box_t copy;
429 
430  /*
431  * We only care about TLV attributes beneath our root
432  */
433  if (!fr_dict_attr_common_parent(root, vp->da, true)) continue;
434 
435  /*
436  * Sanity checks to ensure we're processing attributes
437  * in the right order.
438  */
439  common = fr_dict_attr_common_parent(parent, vp->da, true);
440  if (!common) {
441  fr_strerror_printf("Out of order index attributes. \"%s\" is not a child of \"%s\"",
442  vp->da->name, parent->name);
443  return -1;
444  }
445 
446  /*
447  * Index attribute
448  */
449  if (vp->da->attr == 0) {
450  /*
451  * Print OID from last index/root up to the parent of
452  * the index attribute.
453  */
454  slen = fr_dict_attr_oid_print(&FR_SBUFF_OUT(p, end), parent, vp->da->parent, false);
455  if (slen <= 0) return -1;
456 
457  if (vp->vp_type != FR_TYPE_UINT32) {
458  fr_strerror_printf("Index attribute \"%s\" is not of type \"integer\"", vp->da->name);
459  return -1;
460  }
461 
462  if (slen >= (end - p)) goto oob;
463  p += slen;
464 
465  /*
466  * Add the value of the index attribute as the next
467  * OID component.
468  */
469  len = snprintf(p, end - p, ".%i.", vp->vp_uint32);
470  if (is_truncated(len, end - p)) goto oob;
471 
472  p += len;
473 
474  /*
475  * Set the parent to be the attribute representing
476  * the entry.
477  */
478  parent = fr_dict_attr_child_by_num(vp->da->parent, 1);
479  continue;
480  }
481 
482  /*
483  * Actual TLV attribute
484  */
485  slen = fr_dict_attr_oid_print(&FR_SBUFF_OUT(p, end), parent, vp->da, false);
486  if (slen < 0) return -1;
487 
488  /*
489  * Next attribute should be the type
490  */
491  type_vp = fr_dcursor_next(&cursor);
492  if (!type_vp || (type_vp->da != type)) {
493  fr_strerror_printf("No %s found in response, or occurred out of order", type->name);
494  return -1;
495  }
496  slen = fr_pair_print_value_quoted(&FR_SBUFF_OUT(type_buff, sizeof(type_buff)), type_vp, T_BARE_WORD);
497  if (slen < 0) return -1;
498 
499  type_len = (size_t)slen;
500 
501  /*
502  * Build up the vector
503  *
504  * This represents output for a single varbind attribute
505  */
506  io_vector[0].iov_base = oid_buff;
507  io_vector[0].iov_len = strlen(oid_buff);
508  io_vector[1].iov_base = newline;
509  io_vector[1].iov_len = 1;
510  io_vector[2].iov_base = type_buff;
511  io_vector[2].iov_len = type_len;
512  io_vector[3].iov_base = newline;
513  io_vector[3].iov_len = 1;
514 
515  switch (vp->vp_type) {
516  case FR_TYPE_OCTETS:
517  memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
518  io_vector[4].iov_len = vp->vp_length;
519  break;
520 
521  case FR_TYPE_STRING:
522  memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
523  io_vector[4].iov_len = vp->vp_length;
524  break;
525 
526  case FR_TYPE_STRUCTURAL:
527  fr_assert(0);
528  return -1;
529 
530  default:
531  /*
532  * We need the integer values, not the
533  * enum names. So we copy the box, and
534  * nuke the enum ptr.
535  */
536  fr_value_box_copy_shallow(NULL, &copy, &vp->data);
537  copy.enumv = NULL;
538 
539  slen = fr_value_box_print(&FR_SBUFF_OUT(value_buff, sizeof(value_buff)), &copy, NULL);
540 
541  if (slen < 0) {
542  fr_strerror_const("Insufficient fixed value buffer");
543  return -1;
544  }
545  io_vector[4].iov_base = value_buff;
546  io_vector[4].iov_len = (size_t)slen;
547  break;
548  }
549  io_vector[5].iov_base = newline;
550  io_vector[5].iov_len = 1;
551 
552  DEBUG2("said: %s", (char *)io_vector[0].iov_base);
553  DEBUG2("said: %s", (char *)io_vector[2].iov_base);
554  DEBUG2("said: %s", (char *)io_vector[4].iov_base);
555 
556  if (writev(fd, io_vector, NUM_ELEMENTS(io_vector)) < 0) {
557  fr_strerror_printf("Failed writing varbind result: %s", fr_syserror(errno));
558  return -1;
559  }
560 
561  /*
562  * Reset in case we're encoding multiple values
563  */
564  parent = root;
565  p = oid_buff;
566  type_buff[0] = '\0';
567  written++;
568  }
569 
570  if (!written && (write(fd, "NONE\n", 5)) < 0) {
571  fr_strerror_printf("Failed writing get response: %s", fr_syserror(errno));
572  return -1;
573  }
574 
575  return written;
576 }
577 
578 /** Write the result of a set operation back to net-snmp
579  *
580  * Writes "DONE\n" on success, or an error as described in man snmpd.conf
581  * on error.
582  *
583  * @param fd to write to.
584  * @param error attribute.
585  * @param head of list of attributes to convert and write.
586  * @return
587  * - 0 on success.
588  * - -1 on failure.
589  */
590 static int radsnmp_set_response(int fd, fr_dict_attr_t const *error, fr_pair_list_t *head)
591 {
592  fr_pair_t *vp;
593  char buffer[64];
594  ssize_t slen;
595  struct iovec io_vector[2];
596  char newline[] = "\n";
597 
598  vp = fr_pair_find_by_da(head, NULL, error);
599  if (!vp) {
600  if (write(fd, "DONE\n", 5) < 0) {
601  fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
602  return -1;
603  }
604  return 0;
605  }
606 
608  if (slen < 0) {
609  assert(0);
610  return -1;
611  }
612 
613  io_vector[0].iov_base = buffer;
614  io_vector[0].iov_len = (size_t)slen;
615  io_vector[1].iov_base = newline;
616  io_vector[1].iov_len = 1;
617 
618  DEBUG2("said: %s", buffer);
619 
620  if (writev(fd, io_vector, NUM_ELEMENTS(io_vector)) < 0) {
621  fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
622  return -1;
623  }
624 
625  return 0;
626 }
627 
629 {
631 
632 #define NEXT_LINE(_line, _buffer) \
633 do { \
634  size_t _len; \
635  if (stop) return 0; \
636  errno = 0;\
637  _line = fgets(_buffer, sizeof(_buffer), stdin); \
638  if (_line) { \
639  _len = strlen(_line); \
640  if ((_len > 0) && (_line[_len - 1] == '\n')) _line[_len - 1] = '\0'; \
641  DEBUG2("read: %s", _line); \
642  } \
643 } while (0)
644 
645  /*
646  * Read commands from pass_persist
647  */
648  while (!stop) {
649  radsnmp_command_t command;
650 
651  char buffer[256];
652  char *line;
653  ssize_t slen;
654 
655  fr_dcursor_t cursor;
656  fr_pair_t *vp;
657  fr_packet_t *packet;
658  fr_pair_list_t request_vps;
659 
660  /*
661  * Alloc a new packet so we can start adding
662  * new pairs to it.
663  */
664  packet = radsnmp_alloc(conf, fd);
665  if (!packet) {
666  ERROR("Failed allocating request");
667  return EXIT_FAILURE;
668  }
669  fr_pair_list_init(&request_vps);
670  fr_pair_dcursor_init(&cursor, &request_vps);
671 
673 
674  /*
675  * Determine the type of SNMP operation
676  */
678  switch (command) {
679  case RADSNMP_EXIT:
680  DEBUG("Empty command, exiting");
681  return 0;
682 
683  case RADSNMP_PING:
684  RESPOND_STATIC("PONG");
685  continue;
686 
687  case RADSNMP_SET:
688  {
689  char value_buff[254]; /* RADIUS attribute length + 1 */
690  char *value;
691  char type_str[64];
692  char *p;
694 
695  NEXT_LINE(line, buffer); /* Should be the OID */
696  NEXT_LINE(value, value_buff); /* Should be the value */
697 
698  p = strchr(value, ' ');
699  if (!p) {
700  ERROR("No SNMP type specified (or type/value string was malformed)");
701  RESPOND_STATIC("NONE");
702  continue;
703  }
704 
705  if ((size_t)(p - value) >= sizeof(type_str)) {
706  ERROR("SNMP Type string too long");
707  RESPOND_STATIC("NONE");
708  continue;
709  }
710 
711  strlcpy(type_str, value, (p - value) + 1);
712 
714  if (!type) {
715  ERROR("Unknown type \"%s\"", type_str);
716  RESPOND_STATIC("NONE");
717  continue;
718  }
719 
720  slen = radsnmp_pair_from_oid(conf, conf, &cursor, line, type->value->vb_uint32, p + 1);
721  }
722  break;
723 
724  case RADSNMP_GET:
725  case RADSNMP_GETNEXT:
726  NEXT_LINE(line, buffer); /* Should be the OID */
727  slen = radsnmp_pair_from_oid(conf, conf, &cursor, line, 0, NULL);
728  break;
729 
730  default:
731  ERROR("Unknown command \"%s\"", line);
732  RESPOND_STATIC("NONE");
733  talloc_free(packet);
734  continue;
735  }
736 
737  /*
738  * Deal with any errors from the GET/GETNEXT/SET command
739  */
740  if (slen <= 0) {
741  char *spaces, *text;
742 
743  fr_canonicalize_error(conf, &spaces, &text, slen, line);
744 
745  ERROR("Failed evaluating OID:");
746  ERROR("%s", text);
747  fr_perror("%s^", spaces);
748 
750  talloc_free(text);
751  talloc_free(packet);
752  RESPOND_STATIC("NONE");
753  continue;
754  }
755 
756  /*
757  * Now add an attribute indicating what the
758  * SNMP operation was
759  */
761  vp->vp_uint32 = (unsigned int)command; /* Commands must match dictionary */
762  fr_dcursor_append(&cursor, vp);
763 
764  /*
765  * Add message authenticator or the stats
766  * request will be rejected.
767  */
769  fr_pair_value_memdup(vp, (uint8_t const *)"\0", 1, true);
770  fr_dcursor_append(&cursor, vp);
771 
772  /*
773  * Send the packet
774  */
775  {
776  fr_packet_t *reply = NULL;
777  fr_pair_list_t reply_vps;
778  ssize_t rcode;
779 
780  fd_set set;
781 
782  unsigned int ret;
783  unsigned int i;
784 
785  fr_pair_list_init(&reply_vps);
786  /*
787  * Print the attributes we're about to send
788  */
789  fr_radius_packet_log(&default_log, packet, &reply_vps, false);
790 
791  FD_ZERO(&set); /* clear the set */
792  FD_SET(fd, &set);
793 
794  /*
795  * Any connection issues cause us to exit, so
796  * the connection can be re-initialised on the
797  * next call.
798  */
799  for (i = 0; i < conf->retries; i++) {
800  rcode = fr_packet_send(packet, &request_vps, NULL, conf->secret);
801  if (rcode < 0) {
802  ERROR("Failed sending: %s", fr_syserror(errno));
803  return EXIT_FAILURE;
804  }
805 
806  rcode = select(fd + 1, &set, NULL, NULL, &fr_time_delta_to_timeval(conf->timeout));
807  switch (rcode) {
808  case -1:
809  ERROR("Select failed: %s", fr_syserror(errno));
810  return EXIT_FAILURE;
811 
812  case 0:
813  DEBUG("Response timeout. Retrying %d/%u...", i + 1, conf->retries);
814  continue; /* Timeout */
815 
816  case 1:
817  reply = fr_packet_recv(packet, packet->socket.fd, UDP_FLAGS_NONE,
818  RADIUS_MAX_ATTRIBUTES, false);
819  if (!reply) {
820  fr_perror("Failed receiving reply");
821  recv_error:
822  RESPOND_STATIC("NONE");
823  talloc_free(packet);
824  continue;
825  }
826  if (fr_radius_decode_simple(reply, &reply_vps,
827  reply->data, reply->data_len,
828  packet->vector,
829  conf->secret) < 0) {
830  fr_perror("Failed decoding reply");
831  goto recv_error;
832  }
833  break;
834 
835  default:
836  DEBUG("Invalid select() return value %zd", rcode);
837  return EXIT_FAILURE;
838  }
839  break;
840  }
841 
842  if (!reply) {
843  ERROR("Server didn't respond");
844  return EXIT_FAILURE;
845  }
846 
847  /*
848  * Print the attributes we received in response
849  */
850  fr_radius_packet_log(&default_log, reply, &reply_vps, true);
851 
852  switch (command) {
853  case RADSNMP_GET:
854  case RADSNMP_GETNEXT:
855  ret = radsnmp_get_response(STDOUT_FILENO, conf->snmp_oid_root,
856  attr_freeradius_snmp_type, &reply_vps);
857  switch (ret) {
858  case -1:
859  fr_perror("Failed converting pairs to varbind response");
860  return EXIT_FAILURE;
861 
862  case 0:
863  DEBUG("Empty response");
864  break;
865 
866  default:
867  DEBUG("Returned %u varbind responses", ret);
868  break;
869  }
870  break;
871 
872  case RADSNMP_SET:
873  if (radsnmp_set_response(STDOUT_FILENO, attr_freeradius_snmp_failure, &reply_vps) < 0) {
874  fr_perror("Failed writing SET response");
875  return EXIT_FAILURE;
876  }
877  break;
878 
879  default:
880  assert(0);
881  return EXIT_FAILURE;
882  }
883 
884 
885  talloc_free(packet); /* Frees pairs */
886  }
887  }
888 
889  return EXIT_SUCCESS;
890 }
891 
892 /**
893  *
894  * @hidecallgraph
895  */
896 int main(int argc, char **argv)
897 {
898  int c;
899  char filesecret[256];
900  FILE *fp;
901  int force_af = AF_UNSPEC;
903  int ret;
904  int sockfd;
905  TALLOC_CTX *autofree;
906 
907  /*
908  * Must be called first, so the handler is called last
909  */
911 
913  conf = talloc_zero(autofree, radsnmp_conf_t);
914  conf->proto = IPPROTO_UDP;
915  conf->dict_dir = DICTDIR;
916  conf->raddb_dir = RADDBDIR;
917  conf->secret = talloc_strdup(conf, "testing123");
918  conf->timeout = fr_time_delta_from_sec(3);
919  conf->retries = 5;
920 
921 #ifndef NDEBUG
922  if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
923  fr_perror("radsnmp");
924  fr_exit_now(EXIT_FAILURE);
925  }
926 #endif
927 
928  /*
929  * Need to log to stderr because net-snmp will interpret stdout
930  */
932  talloc_set_log_stderr();
933 
934  while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:l:n:p:P:qr:sS:t:vx")) != -1) switch (c) {
935  case '4':
936  force_af = AF_INET;
937  break;
938 
939  case '6':
940  force_af = AF_INET6;
941  break;
942 
943  case 'D':
944  conf->dict_dir = optarg;
945  break;
946 
947  case 'd':
948  conf->raddb_dir = optarg;
949  break;
950 
951  case 'l':
952  if (strcmp(optarg, "stdout") == 0) { /* stdout goes to net-snmp, so need to switch */
954  break;
955  }
956 
958  default_log.fd = open(optarg, O_WRONLY | O_APPEND | O_CREAT, 0640);
959  if (default_log.fd < 0) {
960  fprintf(stderr, "radsnmp: Failed to open log file %s: %s\n",
961  optarg, fr_syserror(errno));
962  fr_exit_now(EXIT_FAILURE);
963  }
964  break;
965 
966  case 'P':
967  conf->proto_str = optarg;
968  if (strcmp(conf->proto_str, "tcp") != 0) {
969  if (strcmp(conf->proto_str, "udp") != 0) usage();
970  } else {
971  conf->proto = IPPROTO_TCP;
972  }
973  break;
974 
975  case 'r':
976  if (!isdigit((uint8_t) *optarg)) usage();
977  conf->retries = atoi(optarg);
978  if ((conf->retries == 0) || (conf->retries > 1000)) usage();
979  break;
980 
981  case 'S':
982  {
983  char *p;
984  fp = fopen(optarg, "r");
985  if (!fp) {
986  ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
987  fr_exit_now(EXIT_FAILURE);
988  }
989  if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
990  ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
991  fr_exit_now(EXIT_FAILURE);
992  }
993  fclose(fp);
994 
995  /* truncate newline */
996  p = filesecret + strlen(filesecret) - 1;
997  while ((p >= filesecret) &&
998  (*p < ' ')) {
999  *p = '\0';
1000  --p;
1001  }
1002 
1003  if (strlen(filesecret) < 2) {
1004  ERROR("Secret in %s is too short", optarg);
1005  fr_exit_now(EXIT_FAILURE);
1006  }
1007  talloc_free(conf->secret);
1008  conf->secret = talloc_strdup(conf, filesecret);
1009  }
1010  break;
1011 
1012  case 't':
1013  if (fr_time_delta_from_str(&conf->timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
1014  fr_perror("Failed parsing timeout value");
1015  fr_exit_now(EXIT_FAILURE);
1016  }
1017  break;
1018 
1019  case 'v':
1020  DEBUG("%s", radsnmp_version);
1021  fr_exit_now(0);
1022 
1023  case 'x':
1024  fr_debug_lvl++;
1025  break;
1026 
1027  case 'h':
1028  default:
1029  usage();
1030  }
1031  argc -= (optind - 1);
1032  argv += (optind - 1);
1033 
1034  if ((argc < 2) || ((conf->secret == NULL) && (argc < 3))) {
1035  ERROR("Insufficient arguments");
1036  usage();
1037  }
1038  /*
1039  * Mismatch between the binary and the libraries it depends on
1040  */
1042  fr_perror("radsnmp");
1043  return EXIT_FAILURE;
1044  }
1045 
1046  if (fr_dict_autoload(radsnmp_dict) < 0) {
1047  fr_perror("radsnmp");
1048  fr_exit_now(EXIT_FAILURE);
1049  }
1050 
1052  fr_perror("radsnmp");
1053  fr_exit_now(EXIT_FAILURE);
1054  }
1055 
1057  fr_perror("radsnmp");
1058  fr_exit_now(EXIT_FAILURE);
1059  }
1060  fr_strerror_clear(); /* Clear the error buffer */
1061 
1062  /*
1063  * Get the request type
1064  */
1065  if (!isdigit((uint8_t) argv[2][0])) {
1066  int code;
1067 
1069  if (code < 0) {
1070  ERROR("Unrecognised request type \"%s\"", argv[2]);
1071  usage();
1072  }
1073  conf->code = (unsigned int)code;
1074  } else {
1075  conf->code = atoi(argv[2]);
1076  }
1077 
1078  /*
1079  * Resolve hostname.
1080  */
1081  if (fr_inet_pton_port(&conf->server_ipaddr, &conf->server_port, argv[1], -1, force_af, true, true) < 0) {
1082  fr_perror("Failed resolving hostname");
1083  fr_exit_now(EXIT_FAILURE);
1084  }
1085 
1086  /*
1087  * Add the secret
1088  */
1089  if (argv[3]) {
1090  talloc_free(conf->secret);
1091  conf->secret = talloc_strdup(conf, argv[3]);
1092  }
1093 
1095  if (!conf->snmp_root) {
1096  ERROR("Incomplete dictionary: Missing definition for Extended-Attribute-1(%i)."
1097  "Vendor-Specific(%i).FreeRADIUS(%i)",
1099  attr_vendor_specific->attr,
1101  dict_error:
1102  talloc_free(conf);
1103  fr_exit_now(EXIT_FAILURE);
1104  }
1105 
1106  conf->snmp_oid_root = fr_dict_attr_child_by_num(conf->snmp_root, 1);
1107  if (!conf->snmp_oid_root) {
1108  ERROR("Incomplete dictionary: Missing definition for 1.Extended-Attribute-1(%i)."
1109  "Vendor-Specific(%i).FreeRADIUS(%i).FreeRADIUS-Iso(%i)",
1111  attr_vendor_specific->attr,
1113  goto dict_error;
1114  }
1115 
1116  switch (conf->proto) {
1117  case IPPROTO_TCP:
1118  sockfd = fr_socket_client_tcp(NULL, NULL, &conf->server_ipaddr, conf->server_port, true);
1119  break;
1120 
1121  default:
1122  case IPPROTO_UDP:
1123  sockfd = fr_socket_client_udp(NULL, NULL, NULL, &conf->server_ipaddr, conf->server_port, true);
1124  break;
1125  }
1126  if (sockfd < 0) {
1127  ERROR("Failed connecting to server %s:%hu", "foo", conf->server_port);
1128  ret = 1;
1129  goto finish;
1130  }
1131 
1132  fr_set_signal(SIGPIPE, rs_signal_stop);
1133  fr_set_signal(SIGINT, rs_signal_stop);
1134  fr_set_signal(SIGTERM, rs_signal_stop);
1135 #ifdef SIGQUIT
1136  fr_set_signal(SIGQUIT, rs_signal_stop);
1137 #endif
1138 
1139  DEBUG("%s - Starting pass_persist read loop", radsnmp_version);
1140  ret = radsnmp_send_recv(conf, sockfd);
1141  DEBUG("Read loop done");
1142 
1143 finish:
1144  /*
1145  * Everything should be parented from conf
1146  */
1147  talloc_free(conf);
1148 
1149  /*
1150  * ...except the dictionaries
1151  */
1153 
1154  /*
1155  * Ensure our atexit handlers run before any other
1156  * atexit handlers registered by third party libraries.
1157  */
1159 
1160  return ret;
1161 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char int line
Definition: acutest.h:702
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition: atexit.c:160
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition: atexit.c:286
#define RCSID(id)
Definition: build.h:444
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
Definition: dcursor.h:258
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
Definition: dcursor.h:659
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:1215
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:232
#define VENDORPEC_FREERADIUS
Definition: defs.h:146
static char const * spaces
Definition: dependency.c:364
static int sockfd
Definition: dhcpclient.c:56
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition: dict_util.c:1631
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_slen_t fr_dict_attr_by_oid_legacy(fr_dict_t const *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
Get the leaf attribute of an OID string.
Definition: dict_util.c:1719
int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
Process a single OID component.
Definition: dict_util.c:1674
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3647
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:2992
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition: dict_util.c:4179
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Value of an enumerated attribute.
Definition: dict.h:209
Test enumeration values.
Definition: dict_test.h:92
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition: inet.c:923
IPv4/6 prefix.
Definition: merged_model.c:272
talloc_free(reap)
int fr_debug_lvl
Definition: log.c:42
fr_log_t default_log
Definition: log.c:290
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition: log.c:89
@ L_DST_STDERR
Log to stderr.
Definition: log.h:81
@ L_DST_FILES
Log to a file on disk.
Definition: log.h:79
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition: packet.c:38
unsigned short uint16_t
Definition: merged_model.c:31
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
long int ssize_t
Definition: merged_model.c:24
ssize_t fr_dict_attr_oid_print(fr_sbuff_t *out, fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
Definition: merged_model.c:188
unsigned char uint8_t
Definition: merged_model.c:30
unsigned long int size_t
Definition: merged_model.c:25
#define UINT8_MAX
Definition: merged_model.c:32
int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
Definition: misc.c:47
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:278
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition: pair.c:2978
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition: pair.c:2781
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
Definition: pair.c:2586
#define is_truncated(_ret, _max)
Definition: print.h:48
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, uint8_t const *vector, char const *secret)
Simple wrapper for callers who just need a shared secret.
Definition: base.c:1097
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition: base.c:83
int fr_packet_send(fr_packet_t *packet, fr_pair_list_t *list, fr_packet_t const *original, char const *secret)
Reply to the request.
Definition: packet.c:297
void fr_radius_packet_log(fr_log_t const *log, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition: packet.c:497
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_ma)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
Definition: packet.c:211
static TALLOC_CTX * autofree
Definition: radclient-ng.c:104
#define RADIUS_MAX_ATTRIBUTES
Definition: radius.h:39
static rs_t * conf
Definition: radsniff.c:53
fr_dict_attr_t const * snmp_root
SNMP protocol root in the FreeRADIUS dictionary.
Definition: radsnmp.c:78
static size_t radsnmp_command_str_len
Definition: radsnmp.c:74
fr_dict_attr_t const * snmp_op
SNMP operation.
Definition: radsnmp.c:80
#define ERROR(fmt,...)
Definition: radsnmp.c:56
fr_dict_t * dict
Radius protocol dictionary.
Definition: radsnmp.c:77
char const * proto_str
Protocol string.
Definition: radsnmp.c:87
int proto
Protocol TCP/UDP.
Definition: radsnmp.c:86
radsnmp_command_t
Definition: radsnmp.c:58
@ RADSNMP_UNKNOWN
Unknown command.
Definition: radsnmp.c:59
@ RADSNMP_PING
Check server is alive.
Definition: radsnmp.c:60
@ RADSNMP_SET
Set OID.
Definition: radsnmp.c:63
@ RADSNMP_GET
Get an SNMP leaf value.
Definition: radsnmp.c:61
@ RADSNMP_EXIT
Terminate gracefully.
Definition: radsnmp.c:64
@ RADSNMP_GETNEXT
Get next OID.
Definition: radsnmp.c:62
int main(int argc, char **argv)
Definition: radsnmp.c:896
static char const * radsnmp_version
Definition: radsnmp.c:47
fr_dict_attr_t const * snmp_type
SNMP type attribute.
Definition: radsnmp.c:81
static fr_dict_t const * dict_freeradius
Definition: radsnmp.c:98
static bool stop
Definition: radsnmp.c:49
unsigned int retries
Number of retries.
Definition: radsnmp.c:93
static fr_dict_attr_t const * attr_freeradius_snmp_operation
Definition: radsnmp.c:110
fr_dict_attr_t const * snmp_oid_root
First attribute to include at the start of OID responses.
Definition: radsnmp.c:79
char const * raddb_dir
Radius dictionary directory.
Definition: radsnmp.c:83
static fr_dict_t const * dict_radius
Definition: radsnmp.c:99
static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, radsnmp_conf_t *conf, fr_dcursor_t *cursor, char const *oid, int type, char const *value)
Builds attribute representing OID string and adds 'index' attributes where required.
Definition: radsnmp.c:210
static fr_dict_attr_t const * attr_vendor_specific
Definition: radsnmp.c:113
static fr_dict_attr_t const * attr_extended_attribute_1
Definition: radsnmp.c:108
fr_ipaddr_t server_ipaddr
Src IP address.
Definition: radsnmp.c:90
uint16_t server_port
Port to send requests to.
Definition: radsnmp.c:91
static int radsnmp_get_response(int fd, fr_dict_attr_t const *root, fr_dict_attr_t const *type, fr_pair_list_t *head)
Write the result of a get or getnext operation back to net-snmp.
Definition: radsnmp.c:382
fr_dict_autoload_t radsnmp_dict[]
Definition: radsnmp.c:102
uint8_t last_used_id
ID of the last request we sent.
Definition: radsnmp.c:88
char const * dict_dir
Dictionary director.
Definition: radsnmp.c:84
static void rs_signal_stop(UNUSED int sig)
Definition: radsnmp.c:154
static fr_packet_t * radsnmp_alloc(radsnmp_conf_t *conf, int fd)
Allocate a new request using values from radsnmp config.
Definition: radsnmp.c:165
#define DEBUG2(fmt,...)
Definition: radsnmp.c:54
static fr_dict_attr_t const * attr_freeradius_snmp_failure
Definition: radsnmp.c:109
#define RESPOND_STATIC(_cmd)
Definition: radsnmp.c:148
static int radsnmp_send_recv(radsnmp_conf_t *conf, int fd)
Definition: radsnmp.c:628
fr_dict_attr_t const * snmp_failure
SNMP set error attribute.
Definition: radsnmp.c:82
#define NEXT_LINE(_line, _buffer)
unsigned int code
Request type.
Definition: radsnmp.c:85
#define DEBUG(fmt,...)
Definition: radsnmp.c:52
fr_time_delta_t timeout
Definition: radsnmp.c:94
static int radsnmp_set_response(int fd, fr_dict_attr_t const *error, fr_pair_list_t *head)
Write the result of a set operation back to net-snmp.
Definition: radsnmp.c:590
static fr_dict_attr_t const * attr_freeradius_snmp_type
Definition: radsnmp.c:111
fr_dict_attr_autoload_t radsnmp_dict_attr[]
Definition: radsnmp.c:116
static fr_table_num_sorted_t const radsnmp_command_str[]
Definition: radsnmp.c:67
static NEVER_RETURNS void usage(void)
Definition: radsnmp.c:126
char * secret
Shared secret.
Definition: radsnmp.c:95
static fr_dict_attr_t const * attr_message_authenticator
Definition: radsnmp.c:112
#define FR_SBUFF_OUT(_start, _len_or_end)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected UDP socket.
Definition: socket.c:634
int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition: socket.c:729
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
fr_pair_t * vp
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
fr_log_dst_t dst
Log destination.
Definition: log.h:97
int fd
File descriptor to write messages to.
Definition: log.h:112
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition: talloc.h:51
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
Definition: time.c:445
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition: time.h:654
@ FR_TIME_RES_SEC
Definition: time.h:50
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
@ T_BARE_WORD
Definition: token.h:120
#define UDP_FLAGS_NONE
Definition: udp.h:37
static fr_slen_t head
Definition: xlat.h:408
#define FR_DICTIONARY_FILE
Definition: conf.h:7
unsigned int code
Packet code (type).
Definition: packet.h:61
fr_socket_t socket
This packet was received on.
Definition: packet.h:57
int id
Packet ID (used to link requests/responses).
Definition: packet.h:60
uint8_t * data
Packet data (body).
Definition: packet.h:63
size_t data_len
Length of packet data.
Definition: packet.h:64
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
Definition: packet.h:69
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition: pair_print.c:40
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
static fr_slen_t parent
Definition: pair.h:844
int fd
File descriptor if this is a live socket.
Definition: socket.h:81
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition: strerror.c:733
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition: version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition: version.h:81
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5301
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition: value.c:3783