26RCSID(
"$Id: 511802b4fc6733ceb51480a7d9d8c308f6c2684b $")
28#include <freeradius-devel/io/schedule.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/dict.h>
34#include <freeradius-devel/util/misc.h>
35#include <freeradius-devel/util/socket.h>
37#ifdef HAVE_LIBREADLINE
44#if defined(HAVE_READLINE_READLINE_H)
45# include <readline/readline.h>
46# define USE_READLINE (1)
47#elif defined(HAVE_READLINE_H)
49# define USE_READLINE (1)
52#ifdef HAVE_READLINE_HISTORY
53# if defined(HAVE_READLINE_HISTORY_H)
54# include <readline/history.h>
55# define USE_READLINE_HISTORY (1)
56# elif defined(HAVE_HISTORY_H)
58# define USE_READLINE_HISTORY (1)
64#ifdef HAVE_GPERFTOOLS_PROFILER_H
65#include <gperftools/profiler.h>
88 if (prompt && *prompt) puts(prompt);
92 if (!
line)
return NULL;
94 p = strchr(
line,
'\n');
96 fprintf(
my_stderr,
"Input line too long\n");
105 for (p =
line; *p !=
'\0'; p++) {
128 for (p =
line; *p !=
'\0'; p++) {
129 if ((p[0] ==
'\r') ||
138#define radmin_free(_x)
140#define radmin_free free
143#ifndef USE_READLINE_HISTORY
153#define CMD_MAX_ARGV (32)
154#define CMD_MAX_EXPANSIONS (128)
163static int radmin_num_expansions;
167radmin_expansion_walk(
UNUSED const char *text,
int state)
180 if (
current >= radmin_num_expansions)
return NULL;
183 radmin_expansions[
current++] = NULL;
189radmin_completion(
const char *text,
int start,
UNUSED int end)
193 char **expansions = &radmin_expansions[0];
194 char const **expansions_const;
196 rl_attempted_completion_over = 1;
207 memcpy(&expansions_const, &expansions,
sizeof(expansions));
210 if (num <= 0)
return NULL;
212 radmin_num_expansions = num;
214 return rl_completion_matches(text, radmin_expansion_walk);
236 int *context_exit, *context_offset;
252 context_exit = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
253 context_offset = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
254 context_offset[0] = 0;
259 rl_attempted_completion_function = radmin_completion;
261 (void) rl_bind_key(
'?', radmin_help);
277 INFO(
"radmin input was closed - exiting");
298 if (strcmp(
line,
"quit") == 0) {
306 if (strcmp(
line,
"exit") == 0) {
312 prompt = talloc_asprintf(ctx,
"... %s> ", info->
argv[
context - 1]);
333 size - context_offset[
context]);
366 if ((context_offset[
context] + len + 80) >= size) {
367 fprintf(
my_stderr,
"Too many commands!\n");
392 context_offset[argc] = context_offset[
context] + len + 1;
395 prompt = talloc_asprintf(ctx,
"... %s> ", info->
argv[
context - 1]);
406 fprintf(
my_stderr,
"Failed running command.\n");
453 if (info->
argc > 0) {
454 if (strcmp(info->
argv[0],
"all") == 0) {
457 else if (strcmp(info->
argv[0],
"commands") == 0) {
488 fprintf(fp,
"Statistics are only available when the server is started with '-M'.\n");
492 if (strcmp(info->
argv[0],
"total") == 0) {
493 fprintf(fp,
"%zd\n", talloc_total_size(NULL));
497 if (strcmp(info->
argv[0],
"blocks") == 0) {
498 fprintf(fp,
"%zd\n", talloc_total_blocks(NULL));
502 if (strcmp(info->
argv[0],
"full") == 0) {
503 fprintf(fp,
"see stdout of the server for the full report.\n");
512 fprintf(fp_err,
"Must use 'stats memory (blocks|full|total)'\n");
518 int level = atoi(info->
argv[0]);
520 if ((level < 0) || level > 5) {
521 fprintf(fp_err,
"Invalid debug level '%s'\n", info->
argv[0]);
535#ifdef HAVE_GPERFTOOLS_PROFILER_H
539 struct ProfilerState state;
542 info->
argv[0], strlen(info->
argv[0]),
544 fprintf(fp_err,
"Failed setting profile status '%s' - %s\n", info->
argv[0],
fr_strerror());
548 ProfilerGetCurrentState(&state);
554 fprintf(fp_err,
"Profiling is already on, to file %s\n", state.profile_name);
558 if (info->
argc >= 2) {
561 filename = getenv(
"FR_PROFILE_FILENAME");
565 ProfilerStart(filename);
567 pid_t pid = getpid();
568 MEM(filename = talloc_asprintf(NULL,
"/tmp/freeradius-profile.%u.prof", pid));
569 ProfilerStart(filename);
573 }
else if (state.enabled) {
587 struct ProfilerState state;
588 ProfilerGetCurrentState(&state);
590 if (!state.enabled) {
591 fprintf(fp,
"off\n");
595 fprintf(fp,
"on %s\n", state.profile_name);
604 size_t reflen, offset;
610 if (info->
argc <= 0)
return 0;
612 ref = talloc_strdup(talloc_ctx, info->
argv[info->
argc - 1]);
613 text = strrchr(ref,
'.');
627 reflen = strlen(ref);
632 reflen = (text - ref);
660 char const *name1, *check;
696 if (want_section)
continue;
708 MEM(expansions[
count] = str = malloc(reflen + strlen(check) + offset + 1));
709 memcpy(str, ref, reflen);
711 strcpy(str + reflen + offset, check);
727 info->
box[0]->vb_strvalue);
729 fprintf(fp_err,
"No such configuration section.\n");
758 info->
box[0]->vb_strvalue);
760 fprintf(fp_err,
"No such configuration item.\n");
792 fprintf(fp,
"%c%s%c\n", quote,
value, quote);
803 if (info->
argc >= 2) {
806 if (strcmp(info->
argv[1],
"tcp") == 0) {
809 }
else if (strcmp(info->
argv[1],
"udp") == 0) {
813 fprintf(fp_err,
"Unknown proto '%s'.\n", info->
argv[1]);
818 if (client)
goto found;
821 fprintf(fp_err,
"No such client.\n");
825 if (!client)
goto not_found;
829 fprintf(fp,
"shortname\t%s\n", client->
shortname);
830 fprintf(fp,
"secret\t\t%s\n", client->
secret);
832 if (client->
proto == IPPROTO_UDP) {
833 fprintf(fp,
"proto\t\tudp\n");
835 }
else if (client->
proto == IPPROTO_TCP) {
836 fprintf(fp,
"proto\t\ttcp\n");
838 fprintf(fp,
"proto\t\t*\n");
851 fprintf(fp,
"TEST %d\n", info->
argc);
853 for (i = 0; i < info->
argc; i++) {
854 fprintf(fp,
"\t%s\n", info->
argv[i]);
860static 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)
865 if (info->
argc == 0)
return 0;
873 expansions[0] = strdup(
"0");
874 expansions[1] = strdup(
"1");
878 if ((text[0] <
'0') || (text[0] >
'9')) {
885 expansions[0] = p = malloc(2);
897 .help =
"Exit from the current context.",
904 .help =
"Quit and close the command line immediately.",
910 .syntax =
"[(all|commands)]",
912 .help =
"Display list of commands and their help text.",
920 .help =
"Terminate the running server and cause it to exit.",
931 .tab_expand = cmd_test_tab_expand,
932 .help =
"test foo INTEGER",
940 .help =
"Show uptime since the server started.",
946 .help =
"Change settings in the server.",
952 .help =
"Show settings in the server.",
959 .help =
"Show configuration settings in the server.",
964 .parent =
"show config",
967 .help =
"Show a named configuration section",
974 .parent =
"show config",
977 .help =
"Show a named configuration item",
986 .help =
"Show information about a client or clients.",
991 .parent =
"show client",
993 .syntax =
"IPADDR [(udp|tcp)]",
994 .help =
"Show the configuration for a given client.",
1001 .help =
"Show statistics in the server.",
1008 .syntax =
"(blocks|full|total)",
1010 .help =
"Show memory statistics.",
1017 .help =
"Change debug settings.",
1022 .parent =
"set debug",
1024 .syntax =
"INTEGER",
1026 .help =
"Change the debug level.",
1033 .help =
"Show debug settings.",
1038 .parent =
"show debug",
1041 .help =
"show debug level",
1045#ifdef HAVE_GPERFTOOLS_PROFILER_H
1049 .help =
"Change profiler settings.",
1054 .parent =
"set profile",
1056 .syntax =
"BOOL [STRING]",
1057 .func = cmd_set_profile_status,
1058 .help =
"Change the profiler status on/off, and potentially the filename",
1065 .help =
"Show profile settings.",
1070 .parent =
"show profile",
1072 .func = cmd_show_profile_status,
1073 .help =
"show profile status, including filename if profiling is on.",
1089 memcpy(&rl_readline_name, &
config->name,
sizeof(rl_readline_name));
1096 PERROR(
"Failed initializing radmin");
1102 my_stdin = fdopen(std_fd[STDIN_FILENO],
"r");
1111 my_stdout = fdopen(std_fd[STDOUT_FILENO],
"w");
1122 PERROR(
"Failed initializing radmin stderr");
1134 PERROR(
"Failed creating radmin thread");
1138 INFO(
"radmin interface started");
1200 if (ret < 0)
return ret;
1217 char **expansions = &my_expansions[0];
1218 char const **expansions_const;
1220 memcpy(&expansions_const, &expansions,
sizeof(expansions));
1224 if (num <= 0)
return;
1226 for (i = 0; i < num; i++) {
1227 fprintf(fp,
"%s\n", expansions[i]);
1228 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)
static fr_cmd_table_t cmd_table[]
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 second 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.
#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[]
static rc_request_t * current
int fr_schedule_pthread_create(pthread_t *thread, void *(*func)(void *), void *arg)
Creates a new thread using our standard set of options.
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)
#define fr_time()
Allow us to arbitrarily manipulate time.
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 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)