28RCSID(
"$Id: fb5006af72434597e91bb20cee71ca4a459ac396 $")
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>
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__)
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__)
56#define ERROR(fmt, ...) fr_log(&default_log, L_DBG, __FILE__, __LINE__, "radsnmp (error): " fmt, ## __VA_ARGS__)
128 fprintf(stderr,
"Usage: radsnmp [options] server[:port] [<secret>]\n");
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 "
142 fprintf(stderr,
" -v Show program version information.\n");
143 fprintf(stderr,
" -x Increase debug level.\n");
148#define RESPOND_STATIC(_cmd) \
150 DEBUG2("said: %s", _cmd);\
151 if (write(STDOUT_FILENO, _cmd "\n", sizeof(_cmd)) < 0) return 1; \
173 packet->
id =
conf->last_used_id;
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;
211 char const *oid,
int type,
char const *
value)
228 if (p[0] ==
'.') p++;
237 unsigned int num = 0;
283 vp->vp_uint32 = attr;
316 if (!
value)
return slen;
328 switch (
vp->vp_type) {
389 unsigned int written = 0;
397 char value_buff[128];
398 char *p = oid_buff, *end = p +
sizeof(oid_buff);
400 struct iovec io_vector[6];
402 char newline[] =
"\n";
449 if (
vp->
da->attr == 0) {
455 if (slen <= 0)
return -1;
462 if (slen >= (end - p))
goto oob;
469 len =
snprintf(p, end - p,
".%i.",
vp->vp_uint32);
486 if (slen < 0)
return -1;
492 if (!type_vp || (type_vp->
da !=
type)) {
497 if (slen < 0)
return -1;
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;
515 switch (
vp->vp_type) {
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;
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;
545 io_vector[4].iov_base = value_buff;
546 io_vector[4].iov_len = (
size_t)slen;
549 io_vector[5].iov_base = newline;
550 io_vector[5].iov_len = 1;
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);
556 if (writev(fd, io_vector,
NUM_ELEMENTS(io_vector)) < 0) {
570 if (!written && (write(fd,
"NONE\n", 5)) < 0) {
595 struct iovec io_vector[2];
596 char newline[] =
"\n";
600 if (write(fd,
"DONE\n", 5) < 0) {
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;
620 if (writev(fd, io_vector,
NUM_ELEMENTS(io_vector)) < 0) {
632#define NEXT_LINE(_line, _buffer) \
635 if (stop) return 0; \
637 _line = fgets(_buffer, sizeof(_buffer), stdin); \
639 _len = strlen(_line); \
640 if ((_len > 0) && (_line[_len - 1] == '\n')) _line[_len - 1] = '\0'; \
641 DEBUG2("read: %s", _line); \
666 ERROR(
"Failed allocating request");
680 DEBUG(
"Empty command, exiting");
689 char value_buff[254];
698 p = strchr(
value,
' ');
700 ERROR(
"No SNMP type specified (or type/value string was malformed)");
705 if ((
size_t)(p -
value) >=
sizeof(type_str)) {
706 ERROR(
"SNMP Type string too long");
715 ERROR(
"Unknown type \"%s\"", type_str);
745 ERROR(
"Failed evaluating OID:");
761 vp->vp_uint32 = (
unsigned int)command;
799 for (i = 0; i <
conf->retries; i++) {
813 DEBUG(
"Response timeout. Retrying %d/%u...", i + 1,
conf->retries);
836 DEBUG(
"Invalid select() return value %zd", rcode);
843 ERROR(
"Server didn't respond");
859 fr_perror(
"Failed converting pairs to varbind response");
863 DEBUG(
"Empty response");
867 DEBUG(
"Returned %u varbind responses", ret);
874 fr_perror(
"Failed writing SET response");
899 char filesecret[256];
901 int force_af = AF_UNSPEC;
914 conf->proto = IPPROTO_UDP;
915 conf->dict_dir = DICTDIR;
916 conf->raddb_dir = RADDBDIR;
917 conf->secret = talloc_strdup(
conf,
"testing123");
932 talloc_set_log_stderr();
934 while ((c = getopt(argc, argv,
"46c:d:D:f:Fhi:l:n:p:P:qr:sS:t:vx")) != -1)
switch (c) {
944 conf->dict_dir = optarg;
948 conf->raddb_dir = optarg;
952 if (strcmp(optarg,
"stdout") == 0) {
958 default_log.
fd = open(optarg, O_WRONLY | O_APPEND | O_CREAT, 0640);
960 fprintf(stderr,
"radsnmp: Failed to open log file %s: %s\n",
967 conf->proto_str = optarg;
968 if (strcmp(
conf->proto_str,
"tcp") != 0) {
969 if (strcmp(
conf->proto_str,
"udp") != 0)
usage();
971 conf->proto = IPPROTO_TCP;
977 conf->retries = atoi(optarg);
984 fp = fopen(optarg,
"r");
989 if (fgets(filesecret,
sizeof(filesecret), fp) == NULL) {
996 p = filesecret + strlen(filesecret) - 1;
997 while ((p >= filesecret) &&
1003 if (strlen(filesecret) < 2) {
1004 ERROR(
"Secret in %s is too short", optarg);
1008 conf->secret = talloc_strdup(
conf, filesecret);
1014 fr_perror(
"Failed parsing timeout value");
1031 argc -= (optind - 1);
1032 argv += (optind - 1);
1034 if ((argc < 2) || ((
conf->secret == NULL) && (argc < 3))) {
1035 ERROR(
"Insufficient arguments");
1043 return EXIT_FAILURE;
1065 if (!isdigit((
uint8_t) argv[2][0])) {
1070 ERROR(
"Unrecognised request type \"%s\"", argv[2]);
1073 conf->code = (
unsigned int)code;
1075 conf->code = atoi(argv[2]);
1091 conf->secret = talloc_strdup(
conf, argv[3]);
1095 if (!
conf->snmp_root) {
1096 ERROR(
"Incomplete dictionary: Missing definition for Extended-Attribute-1(%i)."
1097 "Vendor-Specific(%i).FreeRADIUS(%i)",
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)",
1116 switch (
conf->proto) {
1127 ERROR(
"Failed connecting to server %s:%hu",
"foo",
conf->server_port);
1141 DEBUG(
"Read loop done");
static int const char char buffer[256]
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
#define NEVER_RETURNS
Should be placed before the function return type.
#define L(_str)
Helper for initialising arrays of string literals.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
#define VENDORPEC_FREERADIUS
static char const * spaces
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
#define fr_dict_autofree(_to_free)
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.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
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.
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
Process a single OID component.
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.
#define fr_dict_autoload(_to_load)
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.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
Value of an enumerated attribute.
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)
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.
@ L_DST_STDERR
Log to stderr.
@ L_DST_FILES
Log to a file on disk.
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
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)
int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
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.
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.
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.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
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.
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.
#define is_truncated(_ret, _max)
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.
fr_table_num_sorted_t const fr_radius_request_name_table[]
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_message_authenticator)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
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.
void fr_radius_packet_log(fr_log_t const *log, fr_packet_t *packet, fr_pair_list_t *list, bool received)
static TALLOC_CTX * autofree
#define RADIUS_MAX_ATTRIBUTES
fr_dict_attr_t const * snmp_root
SNMP protocol root in the FreeRADIUS dictionary.
static size_t radsnmp_command_str_len
fr_dict_attr_t const * snmp_op
SNMP operation.
fr_dict_t * dict
Radius protocol dictionary.
char const * proto_str
Protocol string.
int proto
Protocol TCP/UDP.
@ RADSNMP_UNKNOWN
Unknown command.
@ RADSNMP_PING
Check server is alive.
@ RADSNMP_GET
Get an SNMP leaf value.
@ RADSNMP_EXIT
Terminate gracefully.
@ RADSNMP_GETNEXT
Get next OID.
int main(int argc, char **argv)
static char const * radsnmp_version
fr_dict_attr_t const * snmp_type
SNMP type attribute.
static fr_dict_t const * dict_freeradius
unsigned int retries
Number of retries.
static fr_dict_attr_t const * attr_freeradius_snmp_operation
fr_dict_attr_t const * snmp_oid_root
First attribute to include at the start of OID responses.
char const * raddb_dir
Radius dictionary directory.
static fr_dict_t const * dict_radius
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.
static fr_dict_attr_t const * attr_vendor_specific
static fr_dict_attr_t const * attr_extended_attribute_1
fr_ipaddr_t server_ipaddr
Src IP address.
uint16_t server_port
Port to send requests to.
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.
fr_dict_autoload_t radsnmp_dict[]
uint8_t last_used_id
ID of the last request we sent.
char const * dict_dir
Dictionary director.
static void rs_signal_stop(UNUSED int sig)
static fr_dict_attr_t const * attr_freeradius_snmp_failure
#define RESPOND_STATIC(_cmd)
static int radsnmp_send_recv(radsnmp_conf_t *conf, int fd)
fr_dict_attr_t const * snmp_failure
SNMP set error attribute.
#define NEXT_LINE(_line, _buffer)
unsigned int code
Request type.
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.
static fr_dict_attr_t const * attr_freeradius_snmp_type
fr_dict_attr_autoload_t radsnmp_dict_attr[]
static fr_table_num_sorted_t const radsnmp_command_str[]
static NEVER_RETURNS void usage(void)
static fr_packet_t * radsnmp_alloc(radsnmp_conf_t *conf, int fd)
Allocate a new request using values from radsnmp config.
char * secret
Shared secret.
static fr_dict_attr_t const * attr_message_authenticator
#define FR_SBUFF_OUT(_start, _len_or_end)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
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.
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.
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
fr_log_dst_t dst
Log destination.
int fd
File descriptor to write messages to.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
An element in a lexicographically sorted array of name to num mappings.
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
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.
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
A time delta, a difference in time measured in nanoseconds.
#define FR_DICTIONARY_FILE
unsigned int code
Packet code (type).
fr_socket_t socket
This packet was received on.
int id
Packet ID (used to link requests/responses).
uint8_t * data
Packet data (body).
size_t data_len
Length of packet data.
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
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.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
int fd
File descriptor if this is a live socket.
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
#define FR_TYPE_STRUCTURAL
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
#define RADIUSD_MAGIC_NUMBER
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.
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.