27 RCSID(
"$Id: f5aa08a6b5d642c8cb5e80983f31e851e0cf8b26 $")
39 #ifdef HAVE_SYS_STAT_H
40 # include <sys/stat.h>
43 #ifdef HAVE_LIBREADLINE
48 #if defined(HAVE_READLINE_READLINE_H)
49 # include <readline/readline.h>
50 # define USE_READLINE (1)
51 #elif defined(HAVE_READLINE_H)
52 # include <readline.h>
53 # define USE_READLINE (1)
57 #ifdef HAVE_READLINE_HISTORY
58 # if defined(HAVE_READLINE_HISTORY_H)
59 # include <readline/history.h>
60 # define USE_READLINE_HISTORY (1)
61 # elif defined(HAVE_HISTORY_H)
63 # define USE_READLINE_HISTORY (1)
68 #define LOG_PREFIX "radmin"
70 #include <freeradius-devel/server/cf_parse.h>
71 #include <freeradius-devel/server/cf_file.h>
72 #include <freeradius-devel/server/main_config.h>
73 #include <freeradius-devel/server/radmin.h>
75 #include <freeradius-devel/util/conf.h>
76 #include <freeradius-devel/util/md5.h>
77 #include <freeradius-devel/util/socket.h>
78 #include <freeradius-devel/util/atexit.h>
80 #ifdef USE_READLINE_HISTORY
81 #ifndef READLINE_MAX_HISTORY_LINES
82 # define READLINE_MAX_HISTORY_LINES 1000
150 #define CMD_MAX_EXPANSIONS (128)
151 static int radmin_num_expansions = 0;
155 #define MAX_STACK (64)
164 FILE *output = status ? stderr : stdout;
165 fprintf(output,
"Usage: %s [ args ]\n",
progname);
166 fprintf(output,
" -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
167 fprintf(output,
" -D <dictdir> Set main dictionary directory (defaults to " DICTDIR
").\n");
168 fprintf(output,
" -e command Execute 'command' and then exit.\n");
169 fprintf(output,
" -E Echo commands as they are being executed.\n");
170 fprintf(output,
" -f socket_file Open socket_file directly, without reading radius.conf\n");
171 fprintf(output,
" -h Print usage help information.\n");
172 fprintf(output,
" -i input_file Read commands from 'input_file'.\n");
173 fprintf(output,
" -l <log_file> Commands which are executed will be written to this file.\n");
174 fprintf(output,
" -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
175 fprintf(output,
" -q Reduce output verbosity\n");
176 fprintf(output,
" -s <server> Look in named server for name of control socket.\n");
177 fprintf(output,
" -S <secret> Use argument as shared secret for authentication to the server.\n");
178 fprintf(output,
" -x Increase output verbosity\n");
200 fprintf(stderr,
"%s: Failed looking up host %s: %s\n",
207 fprintf(stderr,
"%s: Failed opening socket %s: %s\n",
227 if (r <= 0)
return r;
230 fprintf(stderr,
"%s: Failed to read challenge.\n",
236 challenge,
sizeof(challenge));
239 if (r <= 0)
return r;
266 if (r <= 0)
return r;
272 fprintf(stdout,
"%s",
buffer);
276 fprintf(stderr,
"ERROR: %s",
buffer);
282 memcpy(&status,
buffer,
sizeof(status));
283 status = ntohl(status);
287 if (r < 4)
return -1;
289 memcpy(¬ify,
buffer,
sizeof(notify));
290 notify = ntohl(notify);
307 MEM(radmin_expansions[radmin_num_expansions] = malloc(len + 1));
308 memcpy(radmin_expansions[radmin_num_expansions], str, len);
309 radmin_expansions[radmin_num_expansions][len] =
'\0';
310 radmin_num_expansions++;
321 fprintf(stderr,
"Unexpected response %02x\n", conduit);
334 char *
buffer,
size_t bufsize)
337 char const *p = command;
343 fprintf(stdout,
"%s\n", command);
350 if (r <= 0)
return r;
379 if (errno == ENOENT) {
380 fprintf(stderr,
"Perhaps you need to run the commands:");
381 fprintf(stderr,
"\tcd /etc/raddb\n");
382 fprintf(stderr,
"\tln -s sites-available/control-socket "
383 "sites-enabled/control-socket\n");
384 fprintf(stderr,
"and then re-start the server?\n");
400 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (
void *)&set,
sizeof(
int));
408 magic = htonl(magic);
409 memcpy(
buffer, &magic,
sizeof(magic));
410 memset(
buffer +
sizeof(magic), 0,
sizeof(magic));
415 fprintf(stderr,
"%s: Error in socket: %s\n",
422 if (r <= 0)
goto do_close;
426 fprintf(stderr,
"%s: Incompatible versions\n",
progname);
433 if (r <= 0)
goto do_close;
450 static char *
my_readline(
char const *prompt, FILE *fp_in, FILE *fp_out)
458 if (prompt && *prompt) puts(prompt);
462 if (!
line)
return NULL;
464 p = strchr(
line,
'\n');
466 fprintf(stderr,
"Input line too long\n");
476 if (
line[0] ==
'#') {
484 for (p =
line; *p !=
'\0'; p++) {
485 if ((p[0] ==
'\r') ||
506 #define radmin_free(_x)
530 fprintf(stderr,
"Command too long\n");
540 if (!isspace((
uint8_t) p[-1]))
break;
555 if (len < 0)
return 0;
560 if ((len >= 5) && strncmp(
cmd_buffer,
"local", 5) == 0) {
582 radmin_expansion_walk(
UNUSED const char *text,
int state)
595 if (
current >= radmin_num_expansions)
return NULL;
599 radmin_expansions[
current++] = NULL;
605 radmin_completion(
const char *text,
int start,
UNUSED int end)
609 rl_attempted_completion_over = 1;
611 radmin_num_expansions = 0;
614 if (len < 0)
return NULL;
621 char **expansions = &radmin_expansions[0];
622 char const **expansions_const;
624 memcpy(&expansions_const, &expansions,
sizeof(expansions));
627 if (num <= 0)
return NULL;
629 radmin_num_expansions = num;
630 return rl_completion_matches(text, radmin_expansion_walk);
635 if (start > 65535)
return NULL;
651 return rl_completion_matches(text, radmin_expansion_walk);
656 #ifndef USE_READLINE_HISTORY
657 # define add_history(line)
658 # define write_history(history_file)
667 char const *uid_name = NULL;
668 char const *gid_name = NULL;
677 if (!
value)
return 0;
679 if (strcmp(
value,
"control") != 0)
return 0;
687 fprintf(stderr,
"%s: Failed parsing 'listen{}' section in 'server %s {...}'\n",
progname, server);
696 if (!
value)
return 0;
701 fprintf(stderr,
"%s: Failed parsing the '%s {}' section in 'server %s {...}'\n",
712 fprintf(stderr,
"%s: Failed parsing listen section 'socket'\n",
progname);
717 fprintf(stderr,
"%s: No path given for socket\n",
progname);
726 if (uid == 0)
return 1;
734 fprintf(stderr,
"%s: Failed parsing listen section 'uid'\n",
progname);
738 if (!uid_name || !*uid_name)
return 1;
740 pwd = getpwnam(uid_name);
742 fprintf(stderr,
"%s: Failed getting UID for user %s: %s\n",
progname, uid_name,
747 if (uid != pwd->pw_uid)
return 0;
752 fprintf(stderr,
"%s: Failed parsing listen section 'gid'\n",
progname);
756 if (!gid_name || !*gid_name)
return 1;
758 grp = getgrnam(gid_name);
760 fprintf(stderr,
"%s: Failed resolving gid of group %s: %s\n",
765 if (gid != grp->gr_gid)
return 0;
772 fprintf(fp,
"We're testing stuff!\n");
785 .help =
"Test stuff",
800 fr_perror(
"Failed parsing local command");
817 if (ret < 0)
return ret;
824 #define MAX_COMMANDS (256)
826 int main(
int argc,
char **argv)
832 char const *
file = NULL;
833 char const *
name =
"radiusd";
834 char const *input_file = NULL;
835 FILE *inputfp = stdin;
836 char const *server = NULL;
840 char const *dict_dir = DICTDIR;
841 #ifdef USE_READLINE_HISTORY
842 char history_file[PATH_MAX];
848 int num_commands = 0;
850 int exit_status = EXIT_SUCCESS;
852 char const *prompt =
"radmin> ";
853 char prompt_buffer[1024];
869 talloc_set_log_stderr();
871 if ((
progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
880 while ((c = getopt(argc, argv,
"d:D:hi:e:Ef:n:qs:S:x")) != -1)
switch (c) {
883 fprintf(stderr,
"%s: -d and -f cannot be used together.\n",
progname);
895 fprintf(stderr,
"%s: Too many '-e'\n",
progname);
919 if (optarg && (strcmp(optarg,
"-") != 0)) input_file = optarg;
938 fprintf(stderr,
"%s: -s and -f cannot be used together.\n",
progname);
1009 fprintf(stderr,
"%s: Could not find virtual server %s {}\n",
progname, server);
1014 if (rcode < 0)
goto error;
1015 if (rcode == 0)
file = NULL;
1022 if (rcode < 0)
goto error;
1023 if (rcode == 1)
break;
1028 fprintf(stderr,
"%s: Could not find control socket in %s (server %s {})\n",
progname,
io_buffer, server);
1043 fprintf(stderr,
"%s: Invalid value for 'radmin' log destination",
progname);
1062 inputfp = fopen(input_file,
"r");
1070 fprintf(stderr,
"%s: Failed to find socket file name\n",
1078 if (input_file || !isatty(STDIN_FILENO)) {
1084 #ifdef USE_READLINE_HISTORY
1086 stifle_history(READLINE_MAX_HISTORY_LINES);
1087 snprintf(history_file,
sizeof(history_file),
"%s/%s", getenv(
"HOME"),
".radmin_history");
1088 read_history(history_file);
1091 rl_attempted_completion_function = radmin_completion;
1100 signal(SIGPIPE, SIG_IGN);
1108 fprintf(stderr,
"%s: Failed registering local commands: %s\n",
1118 if (num_commands > 0) {
1121 for (i = 0; i < num_commands; i++) {
1126 exit_status = EXIT_FAILURE;
1142 printf(
"%s - FreeRADIUS Server administration tool.\n",
radmin_version);
1143 printf(
"Copyright 2008-2019 The FreeRADIUS server project and contributors.\n");
1144 printf(
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
1145 printf(
"PARTICULAR PURPOSE.\n");
1146 printf(
"You may redistribute copies of FreeRADIUS under the terms of the\n");
1147 printf(
"GNU General Public License v2.\n");
1155 (void) rl_bind_key(
'?', radmin_help);
1175 if (strcmp(
line,
"reconnect") == 0) {
1192 if (strcmp(
line,
"quit") == 0) {
1200 if (strcmp(
line,
"exit") == 0) {
1210 prompt =
"radmin> ";
1212 snprintf(prompt_buffer,
sizeof(prompt_buffer),
"... %s> ",
1214 prompt = prompt_buffer;
1226 fprintf(stderr,
"'local' commands MUST be specified all on one line");
1251 exit_status = EXIT_FAILURE;
1260 if (!
quiet) fprintf(stderr,
"... reconnecting ...\n");
1270 fprintf(stderr,
"Failed to connect to server\n");
1275 fprintf(stderr,
"Failed running command\n");
1276 exit_status = EXIT_FAILURE;
1282 fprintf(stderr,
"Too many sub-contexts running command\n");
1283 exit_status = EXIT_FAILURE;
1296 snprintf(prompt_buffer,
sizeof(prompt_buffer),
"... %s> ",
1298 prompt = prompt_buffer;
1322 if (inputfp != stdin) fclose(inputfp);
1328 if (!
quiet) fprintf(stdout,
"\n");
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 CMD_MAX_EXPANSIONS
static char * readline(char const *prompt)
#define NEVER_RETURNS
Should be placed before the function return type.
int cf_file_read(CONF_SECTION *cs, char const *filename)
int cf_section_pass2(CONF_SECTION *cs)
int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt, fr_token_t dflt_quote)
Parses a CONF_PAIR into a C data type, with a default value.
#define FR_ITEM_POINTER(_type, _res_p)
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
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_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
int fr_command_clear(int new_argc, fr_cmd_info_t *info)
Clear out any value boxes etc.
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.
int fr_command_complete(fr_cmd_t *head, char const *text, int start, int max_expansions, char const **expansions)
Do readline-style command completions.
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.
char const * parent
e.g. "show module"
bool runnable
is the command runnable?
ssize_t fr_conduit_write(int fd, fr_conduit_type_t conduit, void const *out, size_t outlen)
ssize_t fr_conduit_read(int fd, fr_conduit_type_t *pconduit, void *out, size_t outlen)
API to provide distinct communication conduits for the radmin protocol.
@ FR_CONDUIT_AUTH_RESPONSE
@ FR_CONDUIT_AUTH_CHALLENGE
fr_dcursor_iter_t void * current
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.
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name, char const *dependent)
(Re-)Initialize the special internal dictionary
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
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_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
int fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal MD5 implementation.
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Stores all information relating to an event list.
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ L_DST_NULL
Discard log messages.
@ L_DST_FILES
Log to a file on disk.
@ L_TIMESTAMP_ON
Always log timestamps.
@ L_DBG_LVL_1
Highest priority debug messages (-x).
@ L_INFO
Informational message.
char * last_command
Last command we executed on this connection.
static char io_buffer[65536]
fr_event_list_t * event_list
Event list this fd is serviced by.
static ssize_t do_challenge(int fd)
static fr_cmd_t * local_cmds
static int client_socket(char const *server)
static bool echo
Main radmin state.
int main(int argc, char **argv)
fr_event_list_t * event_list
Our main event list.
static int do_connect(int *out, char const *file, char const *server)
static char const * radmin_version
static char * my_readline(char const *prompt, FILE *fp_in, FILE *fp_out)
radmin_conn_type_t type
Type of connection.
static int local_command(char *line)
static ssize_t flush_conduits(int fd, char *buffer, size_t bufsize)
static fr_log_t radmin_log
static char const * secret
static fr_cmd_table_t cmd_table[]
bool nonblock
Whether this connection should operate in non-blocking mode.
#define write_history(history_file)
@ RADMIN_CONN_UNIX
Connect via unix socket.
@ RADMIN_CONN_TCP
Connect via TCP.
@ RADMIN_CONN_NONE
Don't know, never connected.
static ssize_t cmd_copy(char const *cmd)
#define add_history(line)
static char const * progname
static char * readline_buffer[1024]
static fr_cmd_info_t local_info
int fd
Control socket descriptor.
char * secret
We use to authenticate ourselves to the server.
static char * stack[MAX_STACK]
static int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
bool connected
Whether this connection is currently connected.
char * server
Path or FQDN of server we're connected to.
static NEVER_RETURNS void usage(int status)
static char cmd_buffer[65536]
static ssize_t run_command(int fd, char const *command, char *buffer, size_t bufsize)
static int check_server(CONF_SECTION *subcs, uid_t uid, gid_t gid, char const **file_p, char const **server_p)
radmin_conn_t * active_conn
Connection to remote entity.
A connection to a server.
@ FR_TYPE_STRING
String of printable characters.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
static TALLOC_CTX * autofree
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
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.
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
char const * file
Path to log file.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
static fr_table_ptr_sorted_t commands[]
#define FR_DICTIONARY_FILE
#define FR_DICTIONARY_INTERNAL_DIR
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.
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
static size_t char ** out