All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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: 151c65722602e38f020201ed32053790adb7f8db $
19  *
20  * @brief map / template functions
21  * @file main/radsnmp.c
22  *
23  * @copyright 2015 The FreeRADIUS server project
24  * @copyright 2015 Network RADIUS SARL <info@networkradius.com>
25  *
26  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
27  */
28 RCSID("$Id: 151c65722602e38f020201ed32053790adb7f8db $")
29 
30 #include <freeradius-devel/conf.h>
31 #include <freeradius-devel/libradius.h>
32 #include <ctype.h>
33 #include <fcntl.h>
34 #include <sys/uio.h>
35 
36 #ifdef HAVE_GETOPT_H
37 # include <getopt.h>
38 #endif
39 
40 #include <assert.h>
41 
42 static char const *radsnmp_version = "radsnmp version " RADIUSD_VERSION_STRING
43 #ifdef RADIUSD_VERSION_COMMIT
44 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
45 #endif
46 ", built on " __DATE__ " at " __TIME__;
47 
48 static bool stop;
49 
50 #undef DEBUG
51 #define DEBUG(fmt, ...) if (fr_debug_lvl > 0) fprintf(fr_log_fp, "radsnmp (debug): " fmt "\n", ## __VA_ARGS__)
52 #undef DEBUG2
53 #define DEBUG2(fmt, ...) if (fr_debug_lvl > 1) fprintf(fr_log_fp, "radsnmp (debug): " fmt "\n", ## __VA_ARGS__)
54 
55 #define ERROR(fmt, ...) fprintf(fr_log_fp, "radsnmp (error): " fmt "\n", ## __VA_ARGS__)
56 
57 typedef enum {
58  RADSNMP_UNKNOWN = -1, //!< Unknown command.
59  RADSNMP_PING = 0, //!< Check server is alive.
60  RADSNMP_GET, //!< Get an SNMP leaf value.
61  RADSNMP_GETNEXT, //!< Get next OID.
62  RADSNMP_SET, //!< Set OID.
63  RADSNMP_EXIT //!< Terminate gracefully.
65 
67  { "PING", RADSNMP_PING }, //!< Liveness command from Net-SNMP
68  { "get", RADSNMP_GET }, //!< Get the value of an OID.
69  { "getnext", RADSNMP_GETNEXT }, //!< Get the next OID in the tree.
70  { "set", RADSNMP_SET }, //!< Set the value of an OID.
71  { "", RADSNMP_EXIT }, //!< Terminate radsnmp.
72  { NULL , -1}
73 };
74 
75 typedef struct radsnmp_conf {
76  fr_dict_t *dict; //!< Radius protocol dictionary.
77  fr_dict_attr_t const *snmp_root; //!< SNMP protocol root in the FreeRADIUS dictionary.
78  fr_dict_attr_t const *snmp_oid_root; //!< First attribute to include at the start of OID responses.
79  fr_dict_attr_t const *snmp_op; //!< SNMP operation.
80  fr_dict_attr_t const *snmp_type; //!< SNMP type attribute.
81  fr_dict_attr_t const *snmp_failure; //!< SNMP set error attribute.
82  char const *radius_dir; //!< Radius dictionary directory.
83  char const *dict_dir; //!< Dictionary director.
84  unsigned int code; //!< Request type.
85  int proto; //!< Protocol TCP/UDP.
86  char const *proto_str; //!< Protocol string.
87  uint8_t last_used_id; //!< ID of the last request we sent.
88 
89  fr_ipaddr_t server_ipaddr; //!< Src IP address.
90  uint16_t server_port; //!< Port to send requests to.
91 
92  unsigned int retries; //!< Number of retries.
93  struct timeval timeout;
94  char const *secret; //!< Shared secret.
96 
97 static void NEVER_RETURNS usage(void)
98 {
99  fprintf(stderr, "Usage: radsnmp [options] server[:port] [<secret>]\n");
100 
101  fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
102  fprintf(stderr, " -4 Use IPv4 address of server\n");
103  fprintf(stderr, " -6 Use IPv6 address of server.\n");
104  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
105  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
106  fprintf(stderr, " -h Print usage help information.\n");
107  fprintf(stderr, " -l <file> Log output to file.\n");
108  fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");;
109  fprintf(stderr, " -S <file> read secret from file, not command line.\n");
110  fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating "
111  "point number).\n");
112  fprintf(stderr, " -v Show program version information.\n");
113  fprintf(stderr, " -x Increase debug level.\n");
114 
115 #ifdef WITH_TCP
116  fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
117 #endif
118 
119  exit(1);
120 }
121 
122 #define RESPOND_STATIC(_cmd) \
123 do {\
124  DEBUG2("said: %s", _cmd);\
125  if (write(STDOUT_FILENO, _cmd "\n", sizeof(_cmd)) < 0) return 1; \
126 } while (0)
127 
128 static void rs_signal_stop(UNUSED int sig)
129 {
130  stop = true;
131 }
132 
133 /** Allocate a new request using values from radsnmp config
134  *
135  * @param conf radsnmp config.
136  * @param fd the request will be sent on.
137  * @return new request.
138  */
140 {
141  RADIUS_PACKET *request;
142 
143  request = fr_radius_alloc(conf, true);
144 
145  request->code = conf->code;
146 
147  request->id = conf->last_used_id;
148  conf->last_used_id = (conf->last_used_id + 1) & UINT8_MAX;
149 
150  memcpy(&request->dst_ipaddr, &conf->server_ipaddr, sizeof(request->dst_ipaddr));
151  request->dst_port = conf->server_port;
152  request->sockfd = fd;
153 
154  return request;
155 }
156 
157 /** Builds attribute representing OID string and adds 'index' attributes where required
158  *
159  * Will convert an OID string in the format @verbatim .1.2.3.4.5.0 @endverbatim
160  * into a pair with a #fr_dict_attr_t of the dictionary attribute matching the OID
161  * string, as evaluated from the specified parent.
162  *
163  * If an OID component does not match a child of a previous OID component, but a child
164  * with attribute number 0 exists, and a child with attribute number 1 also exists,
165  * the child with attribute number 0 will be used as an 'index' pair, and will be
166  * created with the value of the non matching OID component.
167  *
168  * Parsing will then resume using the child with attribute number 1.
169  *
170  * This allows traversals of SNMP tables to be represented by the sequence of pairs
171  * and allows the full range of entry indexes which would not be possible if we represented
172  * table index numbers as TLV attributes.
173  *
174  * @param ctx to allocate new pairs in.
175  * @param cursor to add pairs to.
176  * @param dict for RADIUS protocol.
177  * @param parent Where to start evaluating OID strings from.
178  * @param oid string to evaluate.
179  * @param value to assign to OID attribute (SET operations only).
180  * @return
181  * - >0 on success (how much of the OID string we parsed).
182  * - <=0 on failure (where format error occurred).
183  */
184 static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, vp_cursor_t *cursor,
185  fr_dict_t *dict, fr_dict_attr_t const *parent, char const *oid, char const *value)
186 {
187  ssize_t slen;
188  char const *p = oid;
189  unsigned int attr;
190  fr_dict_attr_t const *index_attr, *da;
191  VALUE_PAIR *vp;
192 
193  if (!oid) return 0;
194 
195  fr_cursor_end(cursor);
196 
197  /*
198  * Trim first.
199  */
200  if (p[0] == '.') p++;
201 
202  /*
203  * Support for indexes. If we can't find an attribute
204  * matching a child at a given level in the OID tree,
205  * look for attribute 0 (type integer) at that level.
206  * We use this to represent the index instead.
207  */
208  for (;;) {
209  unsigned int num = 0;
210 
211  slen = fr_dict_attr_by_oid(dict, &parent, NULL, &attr, p);
212  if (slen > 0) break;
213  p += -(slen);
214 
215  if (fr_dict_oid_component(&num, &p) < 0) break; /* Just advances the pointer */
216  assert(attr == num);
217  p++;
218 
219  /*
220  * Check for an index attribute
221  */
222  index_attr = fr_dict_attr_child_by_num(parent, 0);
223  if (!index_attr) {
224  fr_strerror_printf("Unknown OID component: No index attribute at this level");
225  break;
226  }
227 
228  if (index_attr->type != PW_TYPE_INTEGER) {
229  fr_strerror_printf("Index is not a \"integer\"");
230  break;
231  }
232 
233  /*
234  * By convention SNMP entries are at .1
235  */
236  parent = fr_dict_attr_child_by_num(parent, 1);
237  if (!parent) {
238  fr_strerror_printf("Unknown OID component: No entry attribute at this level");
239  break;
240  }
241 
242  /*
243  * Entry must be a TLV type
244  */
245  if (parent->type != PW_TYPE_TLV) {
246  fr_strerror_printf("Entry is not \"tlv\"");
247  break;
248  }
249 
250  /*
251  * We've skipped over the index attribute, and
252  * the index number should be available in attr.
253  */
254  vp = fr_pair_afrom_da(ctx, index_attr);
255  vp->vp_integer = attr;
256 
257  fr_cursor_insert(cursor, vp);
258  }
259 
260  /*
261  * We errored out processing the OID.
262  */
263  if (slen <= 0) {
264  error:
265  fr_cursor_free(cursor);
266  return slen;
267  }
268 
269  fr_strerror(); /* Clear pending errors */
270 
271  /*
272  * SNMP requests the leaf under the OID
273  * with .0.
274  */
275  if (attr != 0) {
276  da = fr_dict_attr_child_by_num(parent, attr);
277  if (!da) {
278  fr_strerror_printf("Unknown leaf attribute %i", attr);
279  return -(slen);
280  }
281  } else {
282  da = parent;
283  }
284 
285  if (da->type == PW_TYPE_TLV) {
286  fr_strerror_printf("OID must specify a leaf, \"%s\" is a \"tlv\"", da->name);
287  return -(slen);
288  }
289 
290  vp = fr_pair_afrom_da(ctx, da);
291  if (!vp) {
292  fr_strerror_printf("Failed allocating OID attribute");
293  return -(slen);
294  }
295 
296  /*
297  * VALUE_PAIRs with no value need a 1 byte value buffer.
298  */
299  if (!value) {
300  switch (da->type) {
301  case PW_TYPE_STRING:
302  fr_pair_value_bstrncpy(vp, "\0", 1);
303  break;
304 
305  case PW_TYPE_OCTETS:
306  fr_pair_value_memcpy(vp, (uint8_t const *)"\0", 1);
307  break;
308 
309  /*
310  * Fine to leave other values zeroed out.
311  */
312  default:
313  break;
314  }
315  } else {
316  if (fr_pair_value_from_str(vp, value, strlen(value)) < 0) goto error;
317  }
318  fr_cursor_insert(cursor, vp);
319 
320  return slen;
321 }
322 
323 /** Write the result of a get or getnext operation back to net-snmp
324  *
325  * Returns three lines of output per attribute:
326  * - OID string
327  * - type
328  * - value
329  *
330  * Index attributes (num 0) must be in order of depth (shallowest first).
331  *
332  * If no attributes were written, will write "NONE\n" to inform net-snmp
333  * that no value was available at the specified OID.
334  *
335  * @param fd to write to.
336  * @param root of the SNMP portion of the main dictionary.
337  * @param type attribute.
338  * @param head of list of attributes to convert and write.
339  * @return
340  * - >=0 on success (the number of varbind responses written).
341  * - -1 on failure.
342  */
343 static int radsnmp_get_response(int fd,
344  fr_dict_attr_t const *root, fr_dict_attr_t const *type,
345  VALUE_PAIR *head)
346 {
347  vp_cursor_t cursor;
348  VALUE_PAIR *vp;
349  fr_dict_attr_t const *parent = root;
350  unsigned int written = 0;
351 
352  ssize_t slen;
353  size_t len;
354 
355  char type_buff[32]; /* type */
356  size_t type_len = 0;
357  char oid_buff[256];
358  char value_buff[128];
359  char *p = oid_buff, *end = p + sizeof(oid_buff);
360 
361  struct iovec io_vector[6];
362 
363  char newline[] = "\n";
364 
365  type_buff[0] = '\0';
366  /*
367  * @fixme, this is very dependent on ordering
368  *
369  * This code should be reworked when we have proper
370  * attribute grouping to coalesce all related index
371  * attributes under a single request OID.
372  */
373  for (vp = fr_cursor_init(&cursor, &head);
374  vp;
375  vp = fr_cursor_next(&cursor)) {
376  fr_dict_attr_t const *common;
377 
378  /*
379  * Not beneath root, at same level as root...
380  */
381  if (vp->da == type) {
382  type_len = fr_pair_value_snprint(type_buff, sizeof(type_buff), vp, '\0');
383  continue;
384  }
385 
386  /*
387  * We only care about TLV attributes beneath our root
388  */
389  if (!fr_dict_parent_common(root, vp->da, true)) continue;
390 
391  /*
392  * Sanity checks to ensure we're processing attributes
393  * in the right order.
394  */
395  common = fr_dict_parent_common(parent, vp->da, true);
396  if (!common) {
397  fr_strerror_printf("Out of order index attributes. \"%s\" is not a child of \"%s\"",
398  vp->da->name, parent->name);
399  return -1;
400  }
401 
402  /*
403  * Index attribute
404  */
405  if (vp->da->attr == 0) {
406  /*
407  * Print OID from last index/root up to the parent of
408  * the index attribute.
409  */
410  slen = dict_print_attr_oid(p, end - p, common, vp->da->parent);
411  if (slen < 0) return -1;
412 
413  if (vp->da->type != PW_TYPE_INTEGER) {
414  fr_strerror_printf("Index attribute \"%s\" is not of type \"integer\"", vp->da->name);
415  return -1;
416  }
417 
418  if (slen >= (end - p)) {
419  oob:
420  fr_strerror_printf("OID Buffer too small");
421  return -1;
422  }
423  p += slen;
424 
425  /*
426  * Add the value of the index attribute as the next
427  * OID component.
428  */
429  len = snprintf(p, end - p, ".%i.", vp->vp_integer);
430  if (is_truncated(len, end - p)) goto oob;
431 
432  p += len;
433 
434  parent = vp->da->parent;
435  continue;
436  }
437 
438  /*
439  * Actual TLV attribute
440  */
441  slen = dict_print_attr_oid(p, end - p, parent, vp->da);
442  if (slen < 0) return -1;
443 
444  if (type_len == 0) {
445  fr_strerror_printf("No %s found in response, or occurred after value attribute", type->name);
446  return -1;
447  }
448 
449  /*
450  * Build up the vector
451  *
452  * This represents output for a single varbind attribute
453  */
454  io_vector[0].iov_base = oid_buff;
455  io_vector[0].iov_len = strlen(oid_buff);
456  io_vector[1].iov_base = newline;
457  io_vector[1].iov_len = 1;
458  io_vector[2].iov_base = type_buff;
459  io_vector[2].iov_len = type_len;
460  io_vector[3].iov_base = newline;
461  io_vector[3].iov_len = 1;
462 
463  switch (vp->da->type) {
464  case PW_TYPE_OCTETS:
465  memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
466  io_vector[4].iov_len = vp->vp_length;
467  break;
468 
469  case PW_TYPE_STRING:
470  memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
471  io_vector[4].iov_len = vp->vp_length;
472  break;
473 
474  default:
475  len = fr_pair_value_snprint(value_buff, sizeof(value_buff), vp, '\0');
476  if (is_truncated(len, sizeof(value_buff))) {
477  fr_strerror_printf("Insufficient fixed value buffer");
478  return -1;
479  }
480  io_vector[4].iov_base = value_buff;
481  io_vector[4].iov_len = len;
482  break;
483  }
484  io_vector[5].iov_base = newline;
485  io_vector[5].iov_len = 1;
486 
487  DEBUG2("said: %s", (char *)io_vector[0].iov_base);
488  DEBUG2("said: %s", (char *)io_vector[2].iov_base);
489  DEBUG2("said: %s", (char *)io_vector[4].iov_base);
490 
491  if (writev(fd, io_vector, sizeof(io_vector) / sizeof(*io_vector)) < 0) {
492  fr_strerror_printf("Failed writing varbind result: %s", fr_syserror(errno));
493  return -1;
494  }
495 
496  /*
497  * Reset in case we're encoding multiple values
498  */
499  parent = root;
500  p = oid_buff;
501  type_buff[0] = '\0';
502  written++;
503  }
504 
505  if (!written && (write(fd, "NONE\n", 5)) < 0) {
506  fr_strerror_printf("Failed writing get response: %s", fr_syserror(errno));
507  return -1;
508  }
509 
510  return written;
511 }
512 
513 /** Write the result of a set operation back to net-snmp
514  *
515  * Writes "DONE\n" on success, or an error as described in man snmpd.conf
516  * on error.
517  *
518  * @param fd to write to.
519  * @param error attribute.
520  * @param head of list of attributes to convert and write.
521  * @return
522  * - 0 on success.
523  * - -1 on failure.
524  */
525 static int radsnmp_set_response(int fd, fr_dict_attr_t const *error, VALUE_PAIR *head)
526 {
527  VALUE_PAIR *vp;
528  char buffer[64];
529  size_t len;
530  struct iovec io_vector[2];
531  char newline[] = "\n";
532 
533  vp = fr_pair_find_by_da(head, error, TAG_NONE);
534  if (!vp) {
535  if (write(fd, "DONE\n", 5) < 0) {
536  fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
537  return -1;
538  }
539  return 0;
540  }
541 
542  len = fr_pair_value_snprint(buffer, sizeof(buffer), vp, '\0');
543  if (is_truncated(len, sizeof(buffer))) {
544  assert(0);
545  return -1;
546  }
547 
548  io_vector[0].iov_base = buffer;
549  io_vector[0].iov_len = len;
550  io_vector[1].iov_base = newline;
551  io_vector[1].iov_len = 1;
552 
553  DEBUG2("said: %s", buffer);
554 
555  if (writev(fd, io_vector, sizeof(io_vector) / sizeof(*io_vector)) < 0) {
556  fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
557  return -1;
558  }
559 
560  return 0;
561 }
562 
564 {
565  fr_strerror();
566 
567 #define NEXT_LINE(_line, _buffer) \
568 { \
569  size_t _len; \
570  if (stop) return 0; \
571  errno = 0;\
572  _line = fgets(_buffer, sizeof(_buffer), stdin); \
573  if (_line) { \
574  _len = strlen(_line); \
575  if ((_len > 0) && (_line[_len - 1] == '\n')) _line[_len - 1] = '\0'; \
576  DEBUG2("read: %s", _line); \
577  } \
578 }
579  /*
580  * Read commands from pass_persist
581  */
582  while (!stop) {
583  radsnmp_command_t command;
584 
585  char buffer[256];
586  char *line;
587  ssize_t slen;
588 
589  vp_cursor_t cursor;
590  VALUE_PAIR *vp;
591  RADIUS_PACKET *request;
592 
593  /*
594  * Alloc a new request so we can start adding
595  * new pairs to it.
596  */
597  request = radsnmp_alloc(conf, fd);
598  if (!request) {
599  ERROR("Failed allocating request");
600  return EXIT_FAILURE;
601  }
602  fr_cursor_init(&cursor, &request->vps);
603 
604  NEXT_LINE(line, buffer);
605 
606  /*
607  * Determine the type of SNMP operation
608  */
609  command = fr_str2int(radsnmp_command_str, line, RADSNMP_UNKNOWN);
610  switch (command) {
611  case RADSNMP_EXIT:
612  DEBUG("Empty command, exiting");
613  return 0;
614 
615  case RADSNMP_PING:
616  RESPOND_STATIC("PONG");
617  continue;
618 
619  case RADSNMP_SET:
620  {
621  char value_buff[254]; /* RADIUS attribute length + 1 */
622  char *value;
623 
624  NEXT_LINE(line, buffer); /* Should be the OID */
625  NEXT_LINE(value, value_buff); /* Should be the value */
626  slen = radsnmp_pair_from_oid(conf, &cursor, conf->dict, conf->snmp_root, line, value);
627  }
628  break;
629 
630  case RADSNMP_GET:
631  case RADSNMP_GETNEXT:
632  NEXT_LINE(line, buffer); /* Should be the OID */
633  slen = radsnmp_pair_from_oid(conf, &cursor, conf->dict, conf->snmp_root, line, NULL);
634  break;
635 
636  default:
637  ERROR("Unknown command \"%s\"", line);
638  RESPOND_STATIC("NONE");
639  talloc_free(request);
640  continue;
641  }
642 
643  /*
644  * Deal with any errors from the GET/GETNEXT/SET command
645  */
646  if (slen <= 0) {
647  char *spaces, *text;
648 
649  fr_canonicalize_error(conf, &spaces, &text, slen, line);
650 
651  ERROR("Failed evaluating OID:");
652  ERROR("%s", text);
653  ERROR("%s^ %s", spaces, fr_strerror());
654 
655  talloc_free(spaces);
656  talloc_free(text);
657  talloc_free(request);
658  RESPOND_STATIC("NONE");
659  continue;
660  }
661 
662  /*
663  * Now add an attribute indicating what the
664  * SNMP operation was
665  */
666  vp = fr_pair_afrom_da(request, conf->snmp_op);
667  if (!vp) {
668  ERROR("Failed allocating SNMP operation attribute");
669  return EXIT_FAILURE;
670  }
671  vp->vp_integer = (unsigned int)command; /* Commands must match dictionary */
672  fr_cursor_insert(&cursor, vp);
673 
674  /*
675  * Add message authenticator or the stats
676  * request will be rejected.
677  */
678  vp = fr_pair_afrom_num(request, 0, PW_MESSAGE_AUTHENTICATOR);
679  if (!vp) {
680  ERROR("Failed allocating Message-Authenticator attribute");
681  return EXIT_FAILURE;
682  }
683  fr_pair_value_memcpy(vp, (uint8_t const *)"\0", 1);
684  fr_cursor_insert(&cursor, vp);
685 
686  /*
687  * Send the packet
688  */
689  {
690  RADIUS_PACKET *reply = NULL;
691  ssize_t rcode;
692 
693  fd_set set;
694 
695  unsigned int ret;
696  unsigned int i;
697 
698  if (fr_radius_encode(request, NULL, conf->secret) < 0) {
699  ERROR("Failed encoding request: %s", fr_strerror());
700  return EXIT_FAILURE;
701  }
702  if (fr_radius_sign(request, NULL, conf->secret) < 0) {
703  ERROR("Failed signing request: %s", fr_strerror());
704  return EXIT_FAILURE;
705  }
706 
707  /*
708  * Print the attributes we're about to send
709  */
710  if (fr_log_fp) fr_packet_header_print(fr_log_fp, request, false);
711  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, request->vps);
712 #ifndef NDEBUG
713  if (fr_log_fp && (fr_debug_lvl > 3)) fr_radius_print_hex(request);
714 #endif
715 
716  FD_ZERO(&set); /* clear the set */
717  FD_SET(fd, &set);
718 
719  /*
720  * Any connection issues cause us to exit, so
721  * the connection can be re-initialised on the
722  * next call.
723  */
724  for (i = 0; i < conf->retries; i++) {
725  rcode = write(request->sockfd, request->data, request->data_len);
726  if (rcode < 0) {
727  ERROR("Failed sending: %s", fr_syserror(errno));
728  return EXIT_FAILURE;
729  }
730 
731  rcode = select(fd + 1, &set, NULL, NULL, &conf->timeout);
732  switch (rcode) {
733  case -1:
734  ERROR("Select failed: %s", fr_syserror(errno));
735  return EXIT_FAILURE;
736 
737  case 0:
738  DEBUG("Response timeout. Retrying %i/%i...", i + 1, conf->retries);
739  continue; /* Timeout */
740 
741  case 1:
742  reply = fr_radius_recv(request, request->sockfd, 0);
743  if (!reply) {
744  ERROR("Failed receiving reply: %s", fr_strerror());
745  recv_error:
746  RESPOND_STATIC("NONE");
747  talloc_free(request);
748  continue;
749  }
750  if (fr_radius_decode(reply, request, conf->secret) < 0) {
751  ERROR("Failed decoding reply: %s", fr_strerror());
752  goto recv_error;
753  }
754  break;
755 
756  default:
757  DEBUG("Invalid select() return value %zi", rcode);
758  return EXIT_FAILURE;
759  }
760  break;
761  }
762 
763  if (!reply) {
764  ERROR("Server didn't respond");
765  return EXIT_FAILURE;
766  }
767 
768  /*
769  * Print the attributes we received in response
770  */
771  if (fr_log_fp) fr_packet_header_print(fr_log_fp, reply, true);
772  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, reply->vps);
773 #ifndef NDEBUG
774  if (fr_log_fp && (fr_debug_lvl > 3)) fr_radius_print_hex(reply);
775 #endif
776 
777  switch (command) {
778  case RADSNMP_GET:
779  case RADSNMP_GETNEXT:
780  ret = radsnmp_get_response(STDOUT_FILENO, conf->snmp_oid_root,
781  conf->snmp_type, reply->vps);
782  switch (ret) {
783  case -1:
784  ERROR("Failed converting pairs to varbind response: %s", fr_strerror());
785  return EXIT_FAILURE;
786 
787  case 0:
788  DEBUG("Empty response");
789  break;
790 
791  default:
792  DEBUG("Returned %i varbind responses", ret);
793  break;
794  }
795  break;
796 
797  case RADSNMP_SET:
798  if (radsnmp_set_response(STDOUT_FILENO, conf->snmp_failure, reply->vps) < 0) {
799  ERROR("Failed writing SET response: %s", fr_strerror());
800  return EXIT_FAILURE;
801  }
802  break;
803 
804  default:
805  assert(0);
806  return EXIT_FAILURE;
807  }
808 
809 
810  talloc_free(request);
811  }
812  }
813 
814  return EXIT_SUCCESS;
815 }
816 
817 int main(int argc, char **argv)
818 {
819  int c;
820  char filesecret[256];
821  FILE *fp;
822  int force_af = AF_UNSPEC;
824  int ret;
825  int sockfd;
826 
827  fr_log_fp = stderr;
828 
829  conf = talloc_zero(NULL, radsnmp_conf_t);
830  conf->proto = IPPROTO_UDP;
831  conf->dict_dir = DICTDIR;
832  conf->radius_dir = RADDBDIR;
833  conf->secret = "testing123";
834  conf->timeout.tv_sec = 3;
835  conf->retries = 5;
836 
837 #ifndef NDEBUG
838  if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
839  fr_perror("radsnmp");
840  exit(EXIT_FAILURE);
841  }
842 #endif
843 
844  talloc_set_log_stderr();
845 
846  while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:l:n:p:qr:sS:t:vx"
847 #ifdef WITH_TCP
848  "P:"
849 #endif
850  )) != EOF) switch (c) {
851  case '4':
852  force_af = AF_INET;
853  break;
854 
855  case '6':
856  force_af = AF_INET6;
857  break;
858 
859  case 'D':
860  conf->dict_dir = optarg;
861  break;
862 
863  case 'd':
864  conf->radius_dir = optarg;
865  break;
866 
867  case 'l':
868  {
869  int log_fd;
870 
871  if (strcmp(optarg, "stderr") == 0) {
872  fr_log_fp = stderr; /* stdout goes to netsnmp */
873  break;
874  }
875 
876  log_fd = open(optarg, O_WRONLY | O_APPEND | O_CREAT, 0640);
877  if (log_fd < 0) {
878  fprintf(stderr, "radsnmp: Failed to open log file %s: %s\n",
879  optarg, fr_syserror(errno));
880  exit(EXIT_FAILURE);
881  }
882  fr_log_fp = fdopen(log_fd, "a");
883  }
884  break;
885 
886 #ifdef WITH_TCP
887  case 'P':
888  conf->proto_str = optarg;
889  if (strcmp(conf->proto_str, "tcp") != 0) {
890  if (strcmp(conf->proto_str, "udp") != 0) usage();
891  } else {
892  conf->proto = IPPROTO_TCP;
893  }
894  break;
895 
896 #endif
897 
898  case 'r':
899  if (!isdigit((int) *optarg)) usage();
900  conf->retries = atoi(optarg);
901  if ((conf->retries == 0) || (conf->retries > 1000)) usage();
902  break;
903 
904  case 'S':
905  {
906  char *p;
907  fp = fopen(optarg, "r");
908  if (!fp) {
909  ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
910  exit(EXIT_FAILURE);
911  }
912  if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
913  ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
914  exit(EXIT_FAILURE);
915  }
916  fclose(fp);
917 
918  /* truncate newline */
919  p = filesecret + strlen(filesecret) - 1;
920  while ((p >= filesecret) &&
921  (*p < ' ')) {
922  *p = '\0';
923  --p;
924  }
925 
926  if (strlen(filesecret) < 2) {
927  ERROR("Secret in %s is too short", optarg);
928  exit(EXIT_FAILURE);
929  }
930  conf->secret = filesecret;
931  }
932  break;
933 
934  case 't':
935  if (fr_timeval_from_str(&conf->timeout, optarg) < 0) {
936  ERROR("Failed parsing timeout value: %s", fr_strerror());
937  exit(EXIT_FAILURE);
938  }
939  break;
940 
941  case 'v':
942  DEBUG("%s", radsnmp_version);
943  exit(0);
944 
945  case 'x':
946  fr_debug_lvl++;
947  break;
948 
949  case 'h':
950  default:
951  usage();
952  }
953  argc -= (optind - 1);
954  argv += (optind - 1);
955 
956  if ((argc < 2) || ((conf->secret == NULL) && (argc < 3))) {
957  ERROR("Insufficient arguments");
958  usage();
959  }
960  /*
961  * Mismatch between the binary and the libraries it depends on
962  */
964  fr_perror("radsnmp");
965  return EXIT_FAILURE;
966  }
967 
968  if (fr_dict_init(conf, &conf->dict, conf->dict_dir, RADIUS_DICTIONARY, "radius") < 0) {
969  fr_perror("radsnmp");
970  return EXIT_FAILURE;
971  }
972 
973  if (fr_dict_read(conf->dict, conf->radius_dir, RADIUS_DICTIONARY) == -1) {
974  fr_perror("radsnmp");
975  return EXIT_FAILURE;
976  }
977  fr_strerror(); /* Clear the error buffer */
978 
979  if (fr_log_fp) setvbuf(fr_log_fp, NULL, _IONBF, 0);
980 
981  /*
982  * Get the request type
983  */
984  if (!isdigit((int) argv[2][0])) {
985  int code;
986 
987  code = fr_str2int(fr_request_types, argv[2], -1);
988  if (code < 0) {
989  ERROR("Unrecognised request type \"%s\"", argv[2]);
990  usage();
991  }
992  conf->code = (unsigned int)code;
993  } else {
994  conf->code = atoi(argv[2]);
995  }
996 
997  /*
998  * Resolve hostname.
999  */
1000  if (fr_inet_pton_port(&conf->server_ipaddr, &conf->server_port, argv[1], -1, force_af, true, true) < 0) {
1001  ERROR("%s", fr_strerror());
1002  exit(1);
1003  }
1004 
1005  /*
1006  * Add the secret
1007  */
1008  if (argv[3]) conf->secret = argv[3];
1009 
1010  {
1011  fr_dict_attr_t const *parent;
1012 
1013  parent = fr_dict_attr_child_by_num(fr_dict_root(conf->dict), PW_EXTENDED_ATTRIBUTE_1);
1014  if (!parent) {
1015  ERROR("Incomplete dictionary: Missing definition for Extended-Attribute-1");
1016  dict_error:
1017  talloc_free(conf);
1018  exit(1);
1019  }
1020  parent = fr_dict_attr_child_by_num(parent, PW_VENDOR_SPECIFIC);
1021  if (!parent) {
1022  ERROR("Incomplete dictionary: Missing definition for Extended-Attribute-1(%i)."
1023  "Vendor-Specific(%i)", PW_EXTENDED_ATTRIBUTE_1, PW_VENDOR_SPECIFIC);
1024  goto dict_error;
1025  }
1026 
1028  if (!parent) {
1029  ERROR("Incomplete dictionary: Missing definition for Extended-Attribute-1(%i)."
1030  "Vendor-Specific(%i).FreeRADIUS(%i)", PW_EXTENDED_ATTRIBUTE_1, PW_VENDOR_SPECIFIC,
1032  goto dict_error;
1033  }
1034  conf->snmp_root = parent;
1035 
1037  if (!conf->snmp_oid_root) {
1038  ERROR("Incomplete dictionary: Missing definition for Extended-Attribute-1(%i)."
1039  "Vendor-Specific(%i).FreeRADIUS(%i).FreeRADIUS-Iso(%i)",
1040  PW_EXTENDED_ATTRIBUTE_1, PW_VENDOR_SPECIFIC,
1042  goto dict_error;
1043  }
1044  }
1045 
1046  conf->snmp_op = fr_dict_attr_by_name(conf->dict, "FreeRADIUS-SNMP-Operation");
1047  if (!conf->snmp_op) {
1048  ERROR("Incomplete dictionary: Missing definition for \"FreeRADIUS-SNMP-Operation\"");
1049  goto dict_error;
1050  }
1051 
1052  conf->snmp_type = fr_dict_attr_by_name(conf->dict, "FreeRADIUS-SNMP-Type");
1053  if (!conf->snmp_type) {
1054  ERROR("Incomplete dictionary: Missing definition for \"FreeRADIUS-SNMP-Type\"");
1055  goto dict_error;
1056  }
1057 
1058  conf->snmp_failure = fr_dict_attr_by_name(conf->dict, "FreeRADIUS-SNMP-Failure");
1059  if (!conf->snmp_failure) {
1060  ERROR("Incomplete dictionary: Missing definition for \"FreeRADIUS-SNMP-Failure\"");
1061  goto dict_error;
1062  }
1063 
1064  switch (conf->proto) {
1065 #ifdef WITH_TCP
1066  case IPPROTO_TCP:
1067  sockfd = fr_socket_client_tcp(NULL, &conf->server_ipaddr, conf->server_port, true);
1068  break;
1069 #endif
1070 
1071  default:
1072  case IPPROTO_UDP:
1073  sockfd = fr_socket_client_udp(NULL, &conf->server_ipaddr, conf->server_port, true);
1074  break;
1075  }
1076  if (sockfd < 0) {
1077  ERROR("Failed connecting to server %s:%hu", "foo", conf->server_port);
1078  ret = 1;
1079  goto finish;
1080  }
1081 
1082  fr_set_signal(SIGPIPE, rs_signal_stop);
1083  fr_set_signal(SIGINT, rs_signal_stop);
1084  fr_set_signal(SIGTERM, rs_signal_stop);
1085 #ifdef SIGQUIT
1086  fr_set_signal(SIGQUIT, rs_signal_stop);
1087 #endif
1088 
1089  DEBUG("%s - Starting pass_persist read loop", radsnmp_version);
1090  ret = radsnmp_send_recv(conf, sockfd);
1091  DEBUG("Read loop done");
1092 
1093 finish:
1094  if (fr_log_fp) fflush(fr_log_fp);
1095 
1096  /*
1097  * Everything should be parented from conf
1098  */
1099  talloc_free(conf);
1100 
1101  return ret;
1102 }
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.c:3611
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
static int sockfd
Definition: radclient.c:59
static int radsnmp_send_recv(radsnmp_conf_t *conf, int fd)
Definition: radsnmp.c:563
FILE * fr_log_fp
Definition: radius.c:81
int main(int argc, char **argv)
Definition: radsnmp.c:817
void fr_pair_list_fprint(FILE *, VALUE_PAIR const *vp)
Print a list of attributes and enumv.
Definition: pair.c:2266
struct radsnmp_conf radsnmp_conf_t
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
int fr_radius_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Calculate/check digest, and decode radius attributes.
Definition: radius.c:1485
void fr_radius_print_hex(RADIUS_PACKET *packet)
Definition: radius.c:172
unsigned int code
Request type.
Definition: radsnmp.c:84
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
Set OID.
Definition: radsnmp.c:62
static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_t *dict, fr_dict_attr_t const *parent, char const *oid, char const *value)
Builds attribute representing OID string and adds 'index' attributes where required.
Definition: radsnmp.c:184
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
Definition: dict.c:2291
static int radsnmp_get_response(int fd, fr_dict_attr_t const *root, fr_dict_attr_t const *type, VALUE_PAIR *head)
Write the result of a get or getnext operation back to net-snmp.
Definition: radsnmp.c:343
Dictionary attribute.
Definition: dict.h:77
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
char const * radius_dir
Radius dictionary directory.
Definition: radsnmp.c:82
#define VENDORPEC_FREERADIUS
Definition: radius.h:201
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:632
static void NEVER_RETURNS usage(void)
Definition: radsnmp.c:97
#define UNUSED
Definition: libradius.h:134
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
Definition: pair.c:2107
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
Get next OID.
Definition: radsnmp.c:61
fr_dict_t * dict
Radius protocol dictionary.
Definition: radsnmp.c:76
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
unsigned int retries
Number of retries.
Definition: radsnmp.c:92
uint8_t * data
Packet data (body).
Definition: libradius.h:160
static char filesecret[256]
Definition: radeapclient.c:73
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
Terminate gracefully.
Definition: radsnmp.c:63
int fr_debug_lvl
Definition: misc.c:40
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
static bool stop
Definition: radsnmp.c:48
static int force_af
Definition: radeapclient.c:222
FR_NAME_NUMBER const fr_request_types[]
Definition: radius.c:52
int fr_fault_setup(char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:890
#define is_truncated(_ret, _max)
Definition: libradius.h:204
char const * secret
Shared secret.
Definition: radsnmp.c:94
Vendors and attribute names.
Definition: dict.c:61
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
fr_dict_attr_t const * snmp_failure
SNMP set error attribute.
Definition: radsnmp.c:81
struct timeval timeout
Definition: radsnmp.c:93
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:38
void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
Definition: packet.c:962
static int radsnmp_set_response(int fd, fr_dict_attr_t const *error, VALUE_PAIR *head)
Write the result of a set operation back to net-snmp.
Definition: radsnmp.c:525
fr_dict_attr_t const * snmp_oid_root
First attribute to include at the start of OID responses.
Definition: radsnmp.c:78
static char spaces[]
Definition: proto.c:28
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
fr_dict_attr_t const * snmp_root
SNMP protocol root in the FreeRADIUS dictionary.
Definition: radsnmp.c:77
#define STRINGIFY(x)
Definition: build.h:34
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
void void fr_perror(char const *,...) CC_HINT(format(printf
unsigned int attr
Attribute number.
Definition: dict.h:79
unsigned int code
Packet code (type).
Definition: libradius.h:155
int fr_dict_oid_component(unsigned int *out, char const **oid)
Process a single OID component.
Definition: dict.c:3217
#define DEBUG(fmt,...)
Definition: radsnmp.c:51
#define RADIUS_DICTIONARY
Definition: conf.h:7
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
#define ERROR(fmt,...)
Definition: radsnmp.c:55
fr_dict_attr_t const * parent
Immediate parent of this attribute.
Definition: dict.h:82
uint16_t server_port
Port to send requests to.
Definition: radsnmp.c:90
int proto
Protocol TCP/UDP.
Definition: radsnmp.c:85
32 Bit unsigned integer.
Definition: radius.h:34
#define NEXT_LINE(_line, _buffer)
int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t len)
Convert string value to native attribute value.
Definition: pair.c:1840
fr_ipaddr_t server_ipaddr
Src IP address.
Definition: radsnmp.c:89
static rs_t * conf
Definition: radsniff.c:46
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
static RADIUS_PACKET * radsnmp_alloc(radsnmp_conf_t *conf, int fd)
Allocate a new request using values from radsnmp config.
Definition: radsnmp.c:139
Unknown command.
Definition: radsnmp.c:58
VALUE_PAIR * fr_pair_find_by_da(VALUE_PAIR *head, fr_dict_attr_t const *da, int8_t tag)
Find the pair with the matching DAs.
Definition: pair.c:624
#define DEBUG2(fmt,...)
Definition: radsnmp.c:53
char name[1]
Attribute name.
Definition: dict.h:89
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
fr_dict_attr_t const * snmp_type
SNMP type attribute.
Definition: radsnmp.c:80
size_t data_len
Length of packet data.
Definition: libradius.h:161
void void void fr_canonicalize_error(TALLOC_CTX *ctx, char **spaces, char **text, ssize_t slen, char const *msg)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition: log.c:359
size_t dict_print_attr_oid(char *buffer, size_t outlen, fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da)
Build the tlv_stack for the specified DA and encode the path in OID form.
Definition: dict.c:2525
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
int fr_radius_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original, char const *secret)
Encode a packet.
Definition: radius.c:1318
void int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
Definition: misc.c:56
char const * proto_str
Protocol string.
Definition: radsnmp.c:86
fr_dict_attr_t const * fr_dict_parent_common(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.c:3174
static char const * radsnmp_version
Definition: radsnmp.c:42
#define TAG_NONE
Definition: pair.h:192
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
Definition: pair.c:58
IPv4/6 prefix.
Definition: inet.h:41
void fr_cursor_end(vp_cursor_t *cursor)
Moves cursor past the last attribute to the end.
Definition: cursor.c:164
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Definition: pair.c:2043
RADIUS_PACKET * fr_radius_recv(TALLOC_CTX *ctx, int fd, int flags)
Receive UDP client requests, and fill in the basics of a RADIUS_PACKET structure. ...
Definition: radius.c:1050
ssize_t fr_dict_attr_by_oid(fr_dict_t *dict, fr_dict_attr_t const **parent, unsigned int *vendor, unsigned int *attr, char const *oid)
Get the leaf attribute of an OID string.
Definition: dict.c:3263
#define NEVER_RETURNS
Definition: libradius.h:133
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
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
PW_TYPE type
Value type.
Definition: dict.h:80
#define RCSID(id)
Definition: build.h:135
fr_dict_attr_t const * snmp_op
SNMP operation.
Definition: radsnmp.c:79
#define RESPOND_STATIC(_cmd)
Definition: radsnmp.c:122
static const FR_NAME_NUMBER radsnmp_command_str[]
Definition: radsnmp.c:66
void fr_cursor_free(vp_cursor_t *cursor)
Free the current pair and all pairs after it.
Definition: cursor.c:528
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
int fr_timeval_from_str(struct timeval *out, char const *in)
Create timeval from a string.
Definition: misc.c:907
static void rs_signal_stop(UNUSED int sig)
Definition: radsnmp.c:128
char const * dict_dir
Dictionary director.
Definition: radsnmp.c:83
uint8_t last_used_id
ID of the last request we sent.
Definition: radsnmp.c:87
Raw octets.
Definition: radius.h:38
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
int fr_dict_init(TALLOC_CTX *ctx, fr_dict_t **out, char const *dir, char const *fn, char const *name)
(re)initialize a protocol dictionary
Definition: dict.c:2148
Check server is alive.
Definition: radsnmp.c:59
radsnmp_command_t
Definition: radsnmp.c:57
Get an SNMP leaf value.
Definition: radsnmp.c:60
#define RADIUSD_MAGIC_NUMBER
Definition: libradius.h:51
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_t *dict, char const *attr)
Locate a fr_dict_attr_t by its name.
Definition: dict.c:3493
int fr_radius_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original, char const *secret)
Sign a previously encoded packet.
Definition: radius.c:389