26RCSID(
"$Id: d61a9887bc9afc7ccbcdf3014e8059498660148f $")
28#include <freeradius-devel/io/thread.h>
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/server/radmin.h>
33#include <freeradius-devel/util/misc.h>
34#include <freeradius-devel/util/socket.h>
36#ifdef HAVE_LIBREADLINE
42#if defined(HAVE_READLINE_READLINE_H)
43# include <readline/readline.h>
44# define USE_READLINE (1)
45#elif defined(HAVE_READLINE_H)
47# define USE_READLINE (1)
50#ifdef HAVE_READLINE_HISTORY
51# if defined(HAVE_READLINE_HISTORY_H)
52# include <readline/history.h>
53# define USE_READLINE_HISTORY (1)
54# elif defined(HAVE_HISTORY_H)
56# define USE_READLINE_HISTORY (1)
62#ifdef HAVE_GPERFTOOLS_PROFILER_H
63#include <gperftools/profiler.h>
86 if (prompt && *prompt) puts(prompt);
90 if (!
line)
return NULL;
92 p = strchr(
line,
'\n');
94 fprintf(
my_stderr,
"Input line too long\n");
103 for (p =
line; *p !=
'\0'; p++) {
126 for (p =
line; *p !=
'\0'; p++) {
127 if ((p[0] ==
'\r') ||
136#define radmin_free(_x)
138#define radmin_free free
141#ifndef USE_READLINE_HISTORY
151#define CMD_MAX_ARGV (32)
152#define CMD_MAX_EXPANSIONS (128)
161static int radmin_num_expansions;
165radmin_expansion_walk(
UNUSED const char *text,
int state)
178 if (current >= radmin_num_expansions)
return NULL;
180 name = radmin_expansions[current];
181 radmin_expansions[current++] = NULL;
187radmin_completion(
const char *text,
int start,
UNUSED int end)
191 char **expansions = &radmin_expansions[0];
192 char const **expansions_const;
194 rl_attempted_completion_over = 1;
205 memcpy(&expansions_const, &expansions,
sizeof(expansions));
208 if (num <= 0)
return NULL;
210 radmin_num_expansions = num;
212 return rl_completion_matches(text, radmin_expansion_walk);
234 int *context_exit, *context_offset;
250 context_exit = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
251 context_offset = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
252 context_offset[0] = 0;
257 rl_attempted_completion_function = radmin_completion;
259 (void) rl_bind_key(
'?', radmin_help);
275 INFO(
"radmin input was closed - exiting");
296 if (strcmp(
line,
"quit") == 0) {
304 if (strcmp(
line,
"exit") == 0) {
331 size - context_offset[
context]);
367 if ((context_offset[
context] + len + 80) >= size) {
368 fprintf(
my_stderr,
"Too many commands!\n");
393 context_offset[argc] = context_offset[
context] + len + 1;
407 fprintf(
my_stderr,
"Failed running command.\n");
454 if (info->
argc > 0) {
455 if (strcmp(info->
argv[0],
"all") == 0) {
458 else if (strcmp(info->
argv[0],
"commands") == 0) {
489 fprintf(fp,
"Statistics are only available when the server is started with '-M'.\n");
493 if (strcmp(info->
argv[0],
"total") == 0) {
494 fprintf(fp,
"%zd\n", talloc_total_size(NULL));
498 if (strcmp(info->
argv[0],
"blocks") == 0) {
499 fprintf(fp,
"%zd\n", talloc_total_blocks(NULL));
503 if (strcmp(info->
argv[0],
"full") == 0) {
504 fprintf(fp,
"see stdout of the server for the full report.\n");
513 fprintf(fp_err,
"Must use 'stats memory (blocks|full|total)'\n");
519 int level = atoi(info->
argv[0]);
521 if ((level < 0) || level > 5) {
522 fprintf(fp_err,
"Invalid debug level '%s'\n", info->
argv[0]);
536#ifdef HAVE_GPERFTOOLS_PROFILER_H
540 struct ProfilerState state;
543 info->
argv[0], strlen(info->
argv[0]),
545 fprintf(fp_err,
"Failed setting profile status '%s' - %s\n", info->
argv[0],
fr_strerror());
549 ProfilerGetCurrentState(&state);
555 fprintf(fp_err,
"Profiling is already on, to file %s\n", state.profile_name);
559 if (info->
argc >= 2) {
562 filename = getenv(
"FR_PROFILE_FILENAME");
566 ProfilerStart(filename);
568 pid_t pid = getpid();
570 ProfilerStart(filename);
574 }
else if (state.enabled) {
588 struct ProfilerState state;
589 ProfilerGetCurrentState(&state);
591 if (!state.enabled) {
592 fprintf(fp,
"off\n");
596 fprintf(fp,
"on %s\n", state.profile_name);
605 size_t reflen, offset;
611 if (info->
argc <= 0)
return 0;
614 text = strrchr(ref,
'.');
628 reflen = strlen(ref);
633 reflen = (text - ref);
661 char const *name1, *check;
697 if (want_section)
continue;
709 MEM(expansions[
count] = str = malloc(reflen + strlen(check) + offset + 1));
710 memcpy(str, ref, reflen);
712 strcpy(str + reflen + offset, check);
728 info->
box[0]->vb_strvalue);
730 fprintf(fp_err,
"No such configuration section.\n");
759 info->
box[0]->vb_strvalue);
761 fprintf(fp_err,
"No such configuration item.\n");
793 fprintf(fp,
"%c%s%c\n", quote,
value, quote);
804 if (info->
argc >= 2) {
807 if (strcmp(info->
argv[1],
"tcp") == 0) {
810 }
else if (strcmp(info->
argv[1],
"udp") == 0) {
814 fprintf(fp_err,
"Unknown proto '%s'.\n", info->
argv[1]);
819 if (client)
goto found;
822 fprintf(fp_err,
"No such client.\n");
826 if (!client)
goto not_found;
830 fprintf(fp,
"shortname\t%s\n", client->
shortname);
831 fprintf(fp,
"secret\t\t%s\n", client->
secret);
833 if (client->
proto == IPPROTO_UDP) {
834 fprintf(fp,
"proto\t\tudp\n");
836 }
else if (client->
proto == IPPROTO_TCP) {
837 fprintf(fp,
"proto\t\ttcp\n");
839 fprintf(fp,
"proto\t\t*\n");
852 fprintf(fp,
"TEST %d\n", info->
argc);
854 for (i = 0; i < info->
argc; i++) {
855 fprintf(fp,
"\t%s\n", info->
argv[i]);
861static int cmd_test_tab_expand(
UNUSED TALLOC_CTX *talloc_ctx,
UNUSED void *ctx,
fr_cmd_info_t *info,
UNUSED int max_expansions,
char const **expansions)
866 if (info->
argc == 0)
return 0;
874 expansions[0] = strdup(
"0");
875 expansions[1] = strdup(
"1");
879 if ((text[0] <
'0') || (text[0] >
'9')) {
886 expansions[0] = p = malloc(2);
898 .help =
"Exit from the current context.",
905 .help =
"Quit and close the command line immediately.",
911 .syntax =
"[(all|commands)]",
913 .help =
"Display list of commands and their help text.",
921 .help =
"Terminate the running server and cause it to exit.",
932 .tab_expand = cmd_test_tab_expand,
933 .help =
"test foo INTEGER",
941 .help =
"Show uptime since the server started.",
947 .help =
"Change settings in the server.",
953 .help =
"Show settings in the server.",
960 .help =
"Show configuration settings in the server.",
965 .parent =
"show config",
968 .help =
"Show a named configuration section",
975 .parent =
"show config",
978 .help =
"Show a named configuration item",
987 .help =
"Show information about a client or clients.",
992 .parent =
"show client",
994 .syntax =
"IPADDR [(udp|tcp)]",
995 .help =
"Show the configuration for a given client.",
1002 .help =
"Show statistics in the server.",
1009 .syntax =
"(blocks|full|total)",
1011 .help =
"Show memory statistics.",
1018 .help =
"Change debug settings.",
1023 .parent =
"set debug",
1025 .syntax =
"INTEGER",
1027 .help =
"Change the debug level.",
1034 .help =
"Show debug settings.",
1039 .parent =
"show debug",
1042 .help =
"show debug level",
1046#ifdef HAVE_GPERFTOOLS_PROFILER_H
1050 .help =
"Change profiler settings.",
1055 .parent =
"set profile",
1057 .syntax =
"BOOL [STRING]",
1058 .func = cmd_set_profile_status,
1059 .help =
"Change the profiler status on/off, and potentially the filename",
1066 .help =
"Show profile settings.",
1071 .parent =
"show profile",
1073 .func = cmd_show_profile_status,
1074 .help =
"show profile status, including filename if profiling is on.",
1090 memcpy(&rl_readline_name, &
config->name,
sizeof(rl_readline_name));
1097 PERROR(
"Failed initializing radmin");
1103 my_stdin = fdopen(std_fd[STDIN_FILENO],
"r");
1112 my_stdout = fdopen(std_fd[STDOUT_FILENO],
"w");
1129 PERROR(
"Failed initializing radmin stderr");
1141 PERROR(
"Failed creating radmin thread");
1145 INFO(
"radmin interface started");
1207 if (ret < 0)
return ret;
1224 char **expansions = &my_expansions[0];
1225 char const **expansions_const;
1227 memcpy(&expansions_const, &expansions,
sizeof(expansions));
1231 if (num <= 0)
return;
1233 for (i = 0; i < num; i++) {
1234 fprintf(fp,
"%s\n", expansions[i]);
1235 free(expansions[i]);
static int const char char buffer[256]
strcpy(log_entry->msg, buffer)
static int cmd_show_config_section(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static fr_cmd_t * radmin_cmd
static int cmd_exit(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static int cmd_show_config_item(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static int cmd_show_debug_level(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
static void * fr_radmin(UNUSED void *input_ctx)
static int tab_expand_config_section(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions)
static fr_time_t start_time
radmin functions, tables, and callbacks
static int cmd_set_debug_level(UNUSED FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static int cmd_uptime(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
static char * readline(char const *prompt)
static int cmd_stats_memory(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static int cmd_terminate(UNUSED FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
#define CMD_MAX_EXPANSIONS
static main_config_t * radmin_main_config
void fr_radmin_stop(void)
static int tab_expand_config_thing(TALLOC_CTX *talloc_ctx, UNUSED void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions, bool want_section)
static int cmd_help(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
int fr_radmin_run(fr_cmd_info_t *info, FILE *fp, FILE *fp_err, char *str, bool read_only)
Run a command from an input string.
int fr_radmin_start(main_config_t *config, bool cli, int std_fd[static 3])
static char * radmin_partial_line
static fr_cmd_info_t radmin_info
static int cmd_show_client(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
static pthread_t cli_pthread_id
int fr_radmin_register(UNUSED TALLOC_CTX *talloc_ctx, char const *name, void *ctx, fr_cmd_table_t *table)
void fr_radmin_complete(FILE *fp, const char *text, int start)
static char readline_buffer[1024]
static char * radmin_buffer
void fr_radmin_help(FILE *fp, char const *text)
static TALLOC_CTX * radmin_ctx
static int tab_expand_config_item(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
#define cf_item_next(_parent, _curr)
int fr_command_clear(int new_argc, fr_cmd_info_t *info)
Clear out any value boxes etc.
void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, int options)
int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char const *text)
Split a string in-place, updating argv[].
int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only)
Run a particular command.
void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info)
Initialize an fr_cmd_info_t structure.
int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
Do readline-style help completions.
fr_command_register_hook_t fr_command_register_hook
int fr_command_complete(fr_cmd_t *head, char const *text, int start, int max_expansions, char const **expansions)
Do readline-style command completions.
bool fr_command_strncmp(const char *word, const char *name)
int fr_command_add_multi(TALLOC_CTX *talloc_ctx, fr_cmd_t **head, char const *name, void *ctx, fr_cmd_table_t const *table)
Add multiple commands to the global command tree.
int argc
current argument count
fr_value_box_t ** box
value_box version of commands.
bool runnable
is the command runnable?
#define FR_COMMAND_OPTION_HELP
char const * name
e.g. "stats"
char const ** argv
text version of commands
#define FR_COMMAND_OPTION_NONE
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
char const * secret
Secret PSK.
int proto
Protocol number.
char const * shortname
Client nickname.
Describes a host allowed to send packets to the server.
static fr_cmd_table_t cmd_table[]
#define add_history(line)
static int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
bool talloc_memory_report
Print a memory report on what's left unfreed.
CONF_SECTION * root_cs
Root of the server config.
Main server configuration.
void main_loop_signal_raise(int flag)
@ RADIUS_SIGNAL_SELF_EXIT
@ RADIUS_SIGNAL_SELF_TERM
@ FR_TYPE_BOOL
A truth value.
ssize_t fr_fprintf(FILE *fp, char const *fmt,...)
Special version of fprintf which implements custom format specifiers.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
static const conf_parser_t config[]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static int talloc_const_free(void const *ptr)
Free const'd memory.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
#define talloc_strdup(_ctx, _str)
int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
Create a joinable thread.
#define fr_time_sub(_a, _b)
Subtract one time from another.
A time delta, a difference in time measured in nanoseconds.
#define add(_type, _out, _in)
char const * fr_strerror(void)
Get the last library error.
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
#define fr_box_time_delta(_val)