26RCSID(
"$Id: b147255506c8d0e5217091d51bdfb675fa43907c $")
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]);
364 if ((context_offset[
context] + len + 80) >= size) {
365 fprintf(
my_stderr,
"Too many commands!\n");
390 context_offset[argc] = context_offset[
context] + len + 1;
404 fprintf(
my_stderr,
"Failed running command.\n");
451 if (info->
argc > 0) {
452 if (strcmp(info->
argv[0],
"all") == 0) {
455 else if (strcmp(info->
argv[0],
"commands") == 0) {
486 fprintf(fp,
"Statistics are only available when the server is started with '-M'.\n");
490 if (strcmp(info->
argv[0],
"total") == 0) {
491 fprintf(fp,
"%zd\n", talloc_total_size(NULL));
495 if (strcmp(info->
argv[0],
"blocks") == 0) {
496 fprintf(fp,
"%zd\n", talloc_total_blocks(NULL));
500 if (strcmp(info->
argv[0],
"full") == 0) {
501 fprintf(fp,
"see stdout of the server for the full report.\n");
510 fprintf(fp_err,
"Must use 'stats memory (blocks|full|total)'\n");
516 int level = atoi(info->
argv[0]);
518 if ((level < 0) || level > 5) {
519 fprintf(fp_err,
"Invalid debug level '%s'\n", info->
argv[0]);
533#ifdef HAVE_GPERFTOOLS_PROFILER_H
537 struct ProfilerState state;
540 info->
argv[0], strlen(info->
argv[0]),
542 fprintf(fp_err,
"Failed setting profile status '%s' - %s\n", info->
argv[0],
fr_strerror());
546 ProfilerGetCurrentState(&state);
552 fprintf(fp_err,
"Profiling is already on, to file %s\n", state.profile_name);
556 if (info->
argc >= 2) {
559 filename = getenv(
"FR_PROFILE_FILENAME");
563 ProfilerStart(filename);
565 pid_t pid = getpid();
567 ProfilerStart(filename);
571 }
else if (state.enabled) {
585 struct ProfilerState state;
586 ProfilerGetCurrentState(&state);
588 if (!state.enabled) {
589 fprintf(fp,
"off\n");
593 fprintf(fp,
"on %s\n", state.profile_name);
602 size_t reflen, offset;
608 if (info->
argc <= 0)
return 0;
611 text = strrchr(ref,
'.');
625 reflen = strlen(ref);
630 reflen = (text - ref);
658 char const *name1, *check;
694 if (want_section)
continue;
706 MEM(expansions[
count] = str = malloc(reflen + strlen(check) + offset + 1));
707 memcpy(str, ref, reflen);
709 strcpy(str + reflen + offset, check);
725 info->
box[0]->vb_strvalue);
727 fprintf(fp_err,
"No such configuration section.\n");
756 info->
box[0]->vb_strvalue);
758 fprintf(fp_err,
"No such configuration item.\n");
790 fprintf(fp,
"%c%s%c\n", quote,
value, quote);
801 if (info->
argc >= 2) {
804 if (strcmp(info->
argv[1],
"tcp") == 0) {
807 }
else if (strcmp(info->
argv[1],
"udp") == 0) {
811 fprintf(fp_err,
"Unknown proto '%s'.\n", info->
argv[1]);
816 if (client)
goto found;
819 fprintf(fp_err,
"No such client.\n");
823 if (!client)
goto not_found;
827 fprintf(fp,
"shortname\t%s\n", client->
shortname);
828 fprintf(fp,
"secret\t\t%s\n", client->
secret);
830 if (client->
proto == IPPROTO_UDP) {
831 fprintf(fp,
"proto\t\tudp\n");
833 }
else if (client->
proto == IPPROTO_TCP) {
834 fprintf(fp,
"proto\t\ttcp\n");
836 fprintf(fp,
"proto\t\t*\n");
849 fprintf(fp,
"TEST %d\n", info->
argc);
851 for (i = 0; i < info->
argc; i++) {
852 fprintf(fp,
"\t%s\n", info->
argv[i]);
858static 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)
863 if (info->
argc == 0)
return 0;
871 expansions[0] = strdup(
"0");
872 expansions[1] = strdup(
"1");
876 if ((text[0] <
'0') || (text[0] >
'9')) {
883 expansions[0] = p = malloc(2);
895 .help =
"Exit from the current context.",
902 .help =
"Quit and close the command line immediately.",
908 .syntax =
"[(all|commands)]",
910 .help =
"Display list of commands and their help text.",
918 .help =
"Terminate the running server and cause it to exit.",
929 .tab_expand = cmd_test_tab_expand,
930 .help =
"test foo INTEGER",
938 .help =
"Show uptime since the server started.",
944 .help =
"Change settings in the server.",
950 .help =
"Show settings in the server.",
957 .help =
"Show configuration settings in the server.",
962 .parent =
"show config",
965 .help =
"Show a named configuration section",
972 .parent =
"show config",
975 .help =
"Show a named configuration item",
984 .help =
"Show information about a client or clients.",
989 .parent =
"show client",
991 .syntax =
"IPADDR [(udp|tcp)]",
992 .help =
"Show the configuration for a given client.",
999 .help =
"Show statistics in the server.",
1006 .syntax =
"(blocks|full|total)",
1008 .help =
"Show memory statistics.",
1015 .help =
"Change debug settings.",
1020 .parent =
"set debug",
1022 .syntax =
"INTEGER",
1024 .help =
"Change the debug level.",
1031 .help =
"Show debug settings.",
1036 .parent =
"show debug",
1039 .help =
"show debug level",
1043#ifdef HAVE_GPERFTOOLS_PROFILER_H
1047 .help =
"Change profiler settings.",
1052 .parent =
"set profile",
1054 .syntax =
"BOOL [STRING]",
1055 .func = cmd_set_profile_status,
1056 .help =
"Change the profiler status on/off, and potentially the filename",
1063 .help =
"Show profile settings.",
1068 .parent =
"show profile",
1070 .func = cmd_show_profile_status,
1071 .help =
"show profile status, including filename if profiling is on.",
1087 memcpy(&rl_readline_name, &
config->name,
sizeof(rl_readline_name));
1094 PERROR(
"Failed initializing radmin");
1100 my_stdin = fdopen(std_fd[STDIN_FILENO],
"r");
1109 my_stdout = fdopen(std_fd[STDOUT_FILENO],
"w");
1126 PERROR(
"Failed initializing radmin stderr");
1138 PERROR(
"Failed creating radmin thread");
1142 INFO(
"radmin interface started");
1204 if (ret < 0)
return ret;
1221 char **expansions = &my_expansions[0];
1222 char const **expansions_const;
1224 memcpy(&expansions_const, &expansions,
sizeof(expansions));
1228 if (num <= 0)
return;
1230 for (i = 0; i < num; i++) {
1231 fprintf(fp,
"%s\n", expansions[i]);
1232 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)