26 RCSID(
"$Id: 6bfd234d56f0ce0ba9b5c032dbf41d7b9adbba83 $")
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)
48 # include <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>
85 if (prompt && *prompt) puts(prompt);
89 if (!
line)
return NULL;
91 p = strchr(
line,
'\n');
93 fprintf(stderr,
"Input line too long\n");
102 for (p =
line; *p !=
'\0'; p++) {
125 for (p =
line; *p !=
'\0'; p++) {
126 if ((p[0] ==
'\r') ||
135 #define radmin_free(_x)
137 #define radmin_free free
140 #ifndef USE_READLINE_HISTORY
150 #define CMD_MAX_ARGV (32)
151 #define CMD_MAX_EXPANSIONS (128)
160 static int radmin_num_expansions;
164 radmin_expansion_walk(
UNUSED const char *text,
int state)
177 if (
current >= radmin_num_expansions)
return NULL;
180 radmin_expansions[
current++] = NULL;
186 radmin_completion(
const char *text,
int start,
UNUSED int end)
190 char **expansions = &radmin_expansions[0];
191 char const **expansions_const;
193 rl_attempted_completion_over = 1;
204 memcpy(&expansions_const, &expansions,
sizeof(expansions));
207 if (num <= 0)
return NULL;
209 radmin_num_expansions = num;
211 return rl_completion_matches(text, radmin_expansion_walk);
233 int *context_exit, *context_offset;
249 context_exit = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
250 context_offset = talloc_zero_array(ctx,
int,
CMD_MAX_ARGV + 1);
251 context_offset[0] = 0;
256 rl_attempted_completion_function = radmin_completion;
258 (void) rl_bind_key(
'?', radmin_help);
285 if (strcmp(
line,
"quit") == 0) {
286 cmd_exit(stdout, stderr, NULL, info);
293 if (strcmp(
line,
"exit") == 0) {
299 prompt = talloc_asprintf(ctx,
"... %s> ", info->
argv[
context - 1]);
320 size - context_offset[
context]);
353 if ((context_offset[
context] + len + 80) >= size) {
354 fprintf(stderr,
"Too many commands!\n");
379 context_offset[argc] = context_offset[
context] + len + 1;
382 prompt = talloc_asprintf(ctx,
"... %s> ", info->
argv[
context - 1]);
393 fprintf(stderr,
"Failed running command.\n");
436 if (info->
argc > 0) {
437 if (strcmp(info->
argv[0],
"all") == 0) {
440 else if (strcmp(info->
argv[0],
"commands") == 0) {
471 fprintf(fp,
"Statistics are only available when the server is started with '-M'.\n");
475 if (strcmp(info->
argv[0],
"total") == 0) {
476 fprintf(fp,
"%zd\n", talloc_total_size(NULL));
480 if (strcmp(info->
argv[0],
"blocks") == 0) {
481 fprintf(fp,
"%zd\n", talloc_total_blocks(NULL));
485 if (strcmp(info->
argv[0],
"full") == 0) {
486 fprintf(fp,
"see stdout of the server for the full report.\n");
495 fprintf(fp_err,
"Must use 'stats memory (blocks|full|total)'\n");
501 int level = atoi(info->
argv[0]);
503 if ((level < 0) || level > 5) {
504 fprintf(fp_err,
"Invalid debug level '%s'\n", info->
argv[0]);
518 #ifdef HAVE_GPERFTOOLS_PROFILER_H
522 struct ProfilerState state;
525 info->
argv[0], strlen(info->
argv[0]),
527 fprintf(fp_err,
"Failed setting profile status '%s' - %s\n", info->
argv[0],
fr_strerror());
531 ProfilerGetCurrentState(&state);
537 fprintf(fp_err,
"Profiling is already on, to file %s\n", state.profile_name);
541 if (info->
argc >= 2) {
544 filename = getenv(
"FR_PROFILE_FILENAME");
548 ProfilerStart(filename);
550 pid_t pid = getpid();
551 MEM(filename = talloc_asprintf(NULL,
"/tmp/freeradius-profile.%u.prof", pid));
552 ProfilerStart(filename);
556 }
else if (state.enabled) {
570 struct ProfilerState state;
571 ProfilerGetCurrentState(&state);
573 if (!state.enabled) {
574 fprintf(fp,
"off\n");
578 fprintf(fp,
"on %s\n", state.profile_name);
587 size_t reflen, offset;
593 if (info->
argc <= 0)
return 0;
595 ref = talloc_strdup(talloc_ctx, info->
argv[info->
argc - 1]);
596 text = strrchr(ref,
'.');
610 reflen = strlen(ref);
615 reflen = (text - ref);
643 char const *name1, *
check;
679 if (want_section)
continue;
691 MEM(expansions[
count] = str = malloc(reflen + strlen(
check) + offset + 1));
692 memcpy(str, ref, reflen);
710 info->
box[0]->vb_strvalue);
712 fprintf(fp_err,
"No such configuration section.\n");
741 info->
box[0]->vb_strvalue);
743 fprintf(fp_err,
"No such configuration item.\n");
775 fprintf(fp,
"%c%s%c\n", quote,
value, quote);
786 if (info->
argc >= 2) {
789 if (strcmp(info->
argv[1],
"tcp") == 0) {
792 }
else if (strcmp(info->
argv[1],
"udp") == 0) {
796 fprintf(fp_err,
"Unknown proto '%s'.\n", info->
argv[1]);
801 if (client)
goto found;
804 fprintf(fp_err,
"No such client.\n");
808 if (!client)
goto not_found;
812 fprintf(fp,
"shortname\t%s\n", client->
shortname);
813 fprintf(fp,
"secret\t\t%s\n", client->
secret);
815 if (client->
proto == IPPROTO_UDP) {
816 fprintf(fp,
"proto\t\tudp\n");
818 }
else if (client->
proto == IPPROTO_TCP) {
819 fprintf(fp,
"proto\t\ttcp\n");
821 fprintf(fp,
"proto\t\t*\n");
834 fprintf(fp,
"TEST %d\n", info->
argc);
836 for (i = 0; i < info->
argc; i++) {
837 fprintf(fp,
"\t%s\n", info->
argv[i]);
843 static 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)
848 if (info->
argc == 0)
return 0;
856 expansions[0] = strdup(
"0");
857 expansions[1] = strdup(
"1");
861 if ((text[0] <
'0') || (text[0] >
'9')) {
868 expansions[0] = p = malloc(2);
880 .help =
"Exit from the current context.",
887 .help =
"Quit and close the command line immediately.",
893 .syntax =
"[(all|commands)]",
895 .help =
"Display list of commands and their help text.",
903 .help =
"Terminate the running server and cause it to exit.",
914 .tab_expand = cmd_test_tab_expand,
915 .help =
"test foo INTEGER",
923 .help =
"Show uptime since the server started.",
929 .help =
"Change settings in the server.",
935 .help =
"Show settings in the server.",
942 .help =
"Show configuration settings in the server.",
947 .parent =
"show config",
950 .help =
"Show a named configuration section",
957 .parent =
"show config",
960 .help =
"Show a named configuration item",
969 .help =
"Show information about a client or clients.",
974 .parent =
"show client",
976 .syntax =
"IPADDR [(udp|tcp)]",
977 .help =
"Show the configuration for a given client.",
984 .help =
"Show statistics in the server.",
991 .syntax =
"(blocks|full|total)",
993 .help =
"Show memory statistics.",
1000 .help =
"Change debug settings.",
1005 .parent =
"set debug",
1007 .syntax =
"INTEGER",
1009 .help =
"Change the debug level.",
1016 .help =
"Show debug settings.",
1021 .parent =
"show debug",
1024 .help =
"show debug level",
1028 #ifdef HAVE_GPERFTOOLS_PROFILER_H
1032 .help =
"Change profiler settings.",
1037 .parent =
"set profile",
1039 .syntax =
"BOOL [STRING]",
1040 .func = cmd_set_profile_status,
1041 .help =
"Change the profiler status on/off, and potentially the filename",
1048 .help =
"Show profile settings.",
1053 .parent =
"show profile",
1055 .func = cmd_show_profile_status,
1056 .help =
"show profile status, including filename if profiling is on.",
1072 memcpy(&rl_readline_name, &
config->name,
sizeof(rl_readline_name));
1079 PERROR(
"Failed initializing radmin");
1093 PERROR(
"Failed creating radmin thread");
1158 if (ret < 0)
return ret;
1175 char **expansions = &my_expansions[0];
1176 char const **expansions_const;
1178 memcpy(&expansions_const, &expansions,
sizeof(expansions));
1182 if (num <= 0)
return;
1184 for (i = 0; i < num; i++) {
1185 fprintf(fp,
"%s\n", expansions[i]);
1186 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 int tab_expand_config_section(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions)
static void add_history(UNUSED char *line)
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 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)
int fr_radmin_start(main_config_t *config, bool cli)
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.
static char * radmin_partial_line
static char * readline(char const *prompt)
static void * fr_radmin(UNUSED void *input_ctx)
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.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
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.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define cf_item_next(_ci, _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
fr_dcursor_iter_t void * current
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 int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
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_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 char const * proto(int id, int porttype)
#define check(_handle, _len_p)
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)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
#define fr_time()
Allow us to arbitrarily manipulate time.
size_t strlcpy(char *dst, char const *src, size_t siz)
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.
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
char const * fr_strerror(void)
Get the last library error.
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, bool tainted)
#define fr_box_time_delta(_val)