27RCSID(
"$Id: 1428871c9b2f77511ee413a11045012fb7e74223 $")
 
   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) 
   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/skip.h> 
   78#include <freeradius-devel/util/socket.h> 
   79#include <freeradius-devel/util/atexit.h> 
   81#ifdef USE_READLINE_HISTORY 
   82#ifndef READLINE_MAX_HISTORY_LINES 
   83#       define READLINE_MAX_HISTORY_LINES 1000 
  151#define CMD_MAX_EXPANSIONS (128) 
  152static int radmin_num_expansions = 0;
 
  156#define MAX_STACK (64) 
  165        FILE *output = status ? stderr : stdout;
 
  166        fprintf(output, 
"Usage: %s [ args ]\n", 
progname);
 
  167        fprintf(output, 
"  -d raddb_dir    Configuration files are in \"raddbdir/*\".\n");
 
  168        fprintf(output, 
"  -D <dictdir>    Set main dictionary directory (defaults to " DICTDIR 
").\n");
 
  169        fprintf(output, 
"  -e command      Execute 'command' and then exit.\n");
 
  170        fprintf(output, 
"  -E              Echo commands as they are being executed.\n");
 
  171        fprintf(output, 
"  -f socket_file  Open socket_file directly, without reading radius.conf\n");
 
  172        fprintf(output, 
"  -h              Print usage help information.\n");
 
  173        fprintf(output, 
"  -i input_file   Read commands from 'input_file'.\n");
 
  174        fprintf(output, 
"  -l <log_file>   Commands which are executed will be written to this file.\n");
 
  175        fprintf(output, 
"  -n name         Read raddb/name.conf instead of raddb/radiusd.conf\n");
 
  176        fprintf(output, 
"  -q              Reduce output verbosity\n");
 
  177        fprintf(output, 
"  -s <server>     Look in named server for name of control socket.\n");
 
  178        fprintf(output, 
"  -S <secret>     Use argument as shared secret for authentication to the server.\n");
 
  179        fprintf(output, 
"  -x              Increase output verbosity\n");
 
 
  201                fprintf(stderr, 
"%s: Failed looking up host %s: %s\n",
 
  208                fprintf(stderr, 
"%s: Failed opening socket %s: %s\n",
 
 
  228        if (r <= 0) 
return r;
 
  231                fprintf(stderr, 
"%s: Failed to read challenge.\n",
 
  237                    challenge, 
sizeof(challenge));
 
  240        if (r <= 0) 
return r;
 
 
  267                if (r <= 0) 
return r;
 
  273                        fprintf(stdout, 
"%s", 
buffer);
 
  277                        fprintf(stderr, 
"ERROR: %s", 
buffer);
 
  283                        memcpy(&status, 
buffer, 
sizeof(status));
 
  284                        status = ntohl(status);
 
  288                        if (r < 4) 
return -1;
 
  290                        memcpy(¬ify, 
buffer, 
sizeof(notify));
 
  291                        notify = ntohl(notify);
 
  308                                        MEM(radmin_expansions[radmin_num_expansions] = malloc(len + 1));
 
  309                                        memcpy(radmin_expansions[radmin_num_expansions], str, len);
 
  310                                        radmin_expansions[radmin_num_expansions][len] = 
'\0';
 
  311                                        radmin_num_expansions++;
 
  322                        fprintf(stderr, 
"Unexpected response %02x\n", conduit);
 
 
  335                           char *
buffer, 
size_t bufsize)
 
  338        char const *p = command;
 
  344                fprintf(stdout, 
"%s\n", command);
 
  351        if (r <= 0) 
return r;
 
 
  380                        if (errno == ENOENT) {
 
  381                                        fprintf(stderr, 
"Perhaps you need to run the commands:");
 
  382                                        fprintf(stderr, 
"\tcd /etc/raddb\n");
 
  383                                        fprintf(stderr, 
"\tln -s sites-available/control-socket " 
  384                                                "sites-enabled/control-socket\n");
 
  385                                        fprintf(stderr, 
"and then re-start the server?\n");
 
  401                setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (
void *)&set, 
sizeof(
int));
 
  409        magic = htonl(magic);
 
  410        memcpy(
buffer, &magic, 
sizeof(magic));
 
  411        memset(
buffer + 
sizeof(magic), 0, 
sizeof(magic));
 
  416                fprintf(stderr, 
"%s: Error in socket: %s\n",
 
  423        if (r <= 0) 
goto do_close;
 
  427                fprintf(stderr, 
"%s: Incompatible versions\n", 
progname);
 
  434                if (r <= 0) 
goto do_close;
 
 
  451static char *
my_readline(
char const *prompt, FILE *fp_in, FILE *fp_out)
 
  459        if (prompt && *prompt) puts(prompt);
 
  463        if (!
line) 
return NULL;
 
  465        p = strchr(
line, 
'\n');
 
  467                fprintf(stderr, 
"Input line too long\n");
 
  477        if (
line[0] == 
'#') {
 
  485        for (p = 
line; *p != 
'\0'; p++) {
 
  486                if ((p[0] == 
'\r') ||
 
 
  507#define radmin_free(_x) 
  531                fprintf(stderr, 
"Command too long\n");
 
  541                if (!isspace((
uint8_t) p[-1])) 
break;
 
 
  556        if (len < 0) 
return 0;
 
  561        if ((len >= 5) && strncmp(
cmd_buffer, 
"local", 5) == 0) {
 
  583radmin_expansion_walk(
UNUSED const char *text, 
int state)
 
  596    if (
current >= radmin_num_expansions) 
return NULL;
 
  600    radmin_expansions[
current++] = NULL;
 
  606radmin_completion(
const char *text, 
int start, 
UNUSED int end)
 
  610        rl_attempted_completion_over = 1;
 
  612        radmin_num_expansions = 0;
 
  615        if (len < 0) 
return NULL;
 
  622                char **expansions = &radmin_expansions[0];
 
  623                char const **expansions_const;
 
  625                memcpy(&expansions_const, &expansions, 
sizeof(expansions)); 
 
  628                if (num <= 0) 
return NULL;
 
  630                radmin_num_expansions = num;
 
  631                return rl_completion_matches(text, radmin_expansion_walk);
 
  636        if (start > 65535) 
return NULL;
 
  652        return rl_completion_matches(text, radmin_expansion_walk);
 
  657#ifndef USE_READLINE_HISTORY 
  658#       define add_history(line) 
  659#       define write_history(history_file) 
  668        char const      *uid_name = NULL;
 
  669        char const      *gid_name = NULL;
 
  678        if (!
value) 
return 0;
 
  680        if (strcmp(
value, 
"control") != 0) 
return 0;
 
  688                fprintf(stderr, 
"%s: Failed parsing 'listen{}' section in 'server %s {...}'\n", 
progname, server);
 
  697        if (!
value) 
return 0;
 
  702                fprintf(stderr, 
"%s: Failed parsing the '%s {}' section in 'server %s {...}'\n",
 
  713                fprintf(stderr, 
"%s: Failed parsing listen section 'socket'\n", 
progname);
 
  718                fprintf(stderr, 
"%s: No path given for socket\n", 
progname);
 
  727        if (uid == 0) 
return 1;
 
  735                fprintf(stderr, 
"%s: Failed parsing listen section 'uid'\n", 
progname);
 
  739        if (!uid_name || !*uid_name) 
return 1;
 
  741        pwd = getpwnam(uid_name);
 
  743                fprintf(stderr, 
"%s: Failed getting UID for user %s: %s\n", 
progname, uid_name,
 
  748        if (uid != pwd->pw_uid) 
return 0;
 
  753                fprintf(stderr, 
"%s: Failed parsing listen section 'gid'\n", 
progname);
 
  757        if (!gid_name || !*gid_name) 
return 1;
 
  759        grp = getgrnam(gid_name);
 
  761                fprintf(stderr, 
"%s: Failed resolving gid of group %s: %s\n",
 
  766        if (gid != grp->gr_gid) 
return 0;
 
 
  773        fprintf(fp, 
"We're testing stuff!\n");
 
 
  786                .help = 
"Test stuff",
 
 
  801                fr_perror(
"Failed parsing local command");
 
  818        if (ret < 0) 
return ret;
 
 
  825#define MAX_COMMANDS (256) 
  833        char const              *
file = NULL;
 
  834        char const              *
name = 
"radiusd";
 
  835        char const              *input_file = NULL;
 
  836        FILE                    *inputfp = stdin;
 
  837        char const              *server = NULL;
 
  841        char const              *dict_dir = DICTDIR;
 
  842#ifdef USE_READLINE_HISTORY 
  843        char                    history_file[PATH_MAX];
 
  849        int num_commands = 0;
 
  851        int exit_status = EXIT_SUCCESS;
 
  853        char const *prompt = 
"radmin> ";
 
  854        char prompt_buffer[1024];
 
  870        talloc_set_log_stderr();
 
  872        if ((
progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
 
  881        while ((c = getopt(argc, argv, 
"d:D:hi:e:Ef:n:qs:S:x")) != -1) 
switch (c) {
 
  884                                fprintf(stderr, 
"%s: -d and -f cannot be used together.\n", 
progname);
 
  896                                fprintf(stderr, 
"%s: Too many '-e'\n", 
progname);
 
  920                        if (optarg && (strcmp(optarg, 
"-") != 0)) input_file = optarg;
 
  939                                fprintf(stderr, 
"%s: -s and -f cannot be used together.\n", 
progname);
 
 1010                                fprintf(stderr, 
"%s: Could not find virtual server %s {}\n", 
progname, server);
 
 1015                        if (rcode < 0) 
goto error;
 
 1016                        if (rcode == 0) 
file = NULL;
 
 1023                                if (rcode < 0) 
goto error;
 
 1024                                if (rcode == 1) 
break;
 
 1029                        fprintf(stderr, 
"%s: Could not find control socket in %s (server %s {})\n", 
progname, 
io_buffer, server);
 
 1044                                                fprintf(stderr, 
"%s: Invalid value for 'radmin' log destination", 
progname);
 
 1063                inputfp = fopen(input_file, 
"r");
 
 1071                fprintf(stderr, 
"%s: Failed to find socket file name\n",
 
 1079        if (input_file || !isatty(STDIN_FILENO)) {
 
 1085#ifdef USE_READLINE_HISTORY 
 1087                stifle_history(READLINE_MAX_HISTORY_LINES);
 
 1088                snprintf(history_file, 
sizeof(history_file), 
"%s/%s", getenv(
"HOME"), 
".radmin_history");
 
 1089                read_history(history_file);
 
 1092                rl_attempted_completion_function = radmin_completion;
 
 1101        signal(SIGPIPE, SIG_IGN);
 
 1109                fprintf(stderr, 
"%s: Failed registering local commands: %s\n",
 
 1119        if (num_commands > 0) {
 
 1122                for (i = 0; i < num_commands; i++) {
 
 1127                                exit_status = EXIT_FAILURE;
 
 1143                printf(
"%s - FreeRADIUS Server administration tool.\n", 
radmin_version);
 
 1144                printf(
"Copyright 2008-2019 The FreeRADIUS server project and contributors.\n");
 
 1145                printf(
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
 
 1146                printf(
"PARTICULAR PURPOSE.\n");
 
 1147                printf(
"You may redistribute copies of FreeRADIUS under the terms of the\n");
 
 1148                printf(
"GNU General Public License v2.\n");
 
 1156        (void) rl_bind_key(
'?', radmin_help);
 
 1170                if (!*
line) 
goto next;
 
 1176                if (strcmp(
line, 
"reconnect") == 0) {
 
 1193                if (strcmp(
line, 
"quit") == 0) {
 
 1201                if (strcmp(
line, 
"exit") == 0) {
 
 1211                                prompt = 
"radmin> ";
 
 1213                                snprintf(prompt_buffer, 
sizeof(prompt_buffer), 
"... %s> ",
 
 1215                                prompt = prompt_buffer;
 
 1227                                fprintf(stderr, 
"'local' commands MUST be specified all on one line");
 
 1252                        exit_status = EXIT_FAILURE;
 
 1261                        if (!quiet) fprintf(stderr, 
"... reconnecting ...\n");
 
 1271                        fprintf(stderr, 
"Failed to connect to server\n");
 
 1276                        fprintf(stderr, 
"Failed running command\n");
 
 1277                        exit_status = EXIT_FAILURE;
 
 1283                                fprintf(stderr, 
"Too many sub-contexts running command\n");
 
 1284                                exit_status = EXIT_FAILURE;
 
 1297                        snprintf(prompt_buffer, 
sizeof(prompt_buffer), 
"... %s> ",
 
 1299                        prompt = prompt_buffer;
 
 1323        if (inputfp != stdin) fclose(inputfp);
 
 1329        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.
 
static TALLOC_CTX * autofree
 
static char * readline(char const *prompt)
 
#define CMD_MAX_EXPANSIONS
 
static fr_cmd_table_t cmd_table[]
 
static char readline_buffer[1024]
 
#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.
 
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_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.
 
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_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
 
#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
 
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.
 
static NEVER_RETURNS void usage(void)
 
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_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.
 
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 char * my_readline(char const *prompt, FILE *fp_in, FILE *fp_out)
 
static int do_connect(int *out, char const *file, char const *server)
 
static char const  * radmin_version
 
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
 
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 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 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.
 
static rc_request_t * current
 
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
 
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)
 
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
 
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.
 
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