24 RCSID(
"$Id: d705b0373e8056c409aa5a075b2cd5bb29d51e04 $")
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/md5.h>
28 #include <freeradius-devel/channel.h>
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
41 #ifdef HAVE_LIBREADLINE
43 #if defined(HAVE_READLINE_READLINE_H)
44 # include <readline/readline.h>
45 # define USE_READLINE (1)
46 #elif defined(HAVE_READLINE_H)
47 # include <readline.h>
48 # define USE_READLINE (1)
51 #ifdef HAVE_READLINE_HISTORY
52 # if defined(HAVE_READLINE_HISTORY_H)
53 # include <readline/history.h>
54 # define USE_READLINE_HISTORY (1)
55 # elif defined(HAVE_HISTORY_H)
57 # define USE_READLINE_HISTORY (1)
69 #ifdef RADIUSD_VERSION_COMMIT
70 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT)
")"
72 ", built on " __DATE__
" at " __TIME__;
83 static char const *
secret =
"testing123";
95 return waitpid(pid, status, 0);
101 FILE *output = status ? stderr : stdout;
102 fprintf(output,
"Usage: %s [ args ]\n", progname);
103 fprintf(output,
" -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
104 fprintf(stderr,
" -D <dictdir> Set main dictionary directory (defaults to " DICTDIR
").\n");
105 fprintf(output,
" -e command Execute 'command' and then exit.\n");
106 fprintf(output,
" -E Echo commands as they are being executed.\n");
107 fprintf(output,
" -f socket_file Open socket_file directly, without reading radius.conf\n");
108 fprintf(output,
" -h Print usage help information.\n");
109 fprintf(output,
" -i input_file Read commands from 'input_file'.\n");
110 fprintf(output,
" -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
111 fprintf(output,
" -q Quiet mode.\n");
121 char *p, buffer[1024];
123 strlcpy(buffer, server,
sizeof(buffer));
125 p = strchr(buffer,
':');
133 if (
fr_inet_hton(&ipaddr, AF_INET, buffer,
false) < 0) {
134 fprintf(stderr,
"%s: Failed looking up host %s: %s\n",
141 fprintf(stderr,
"%s: Failed opening socket %s: %s\n",
153 uint8_t challenge[16];
161 if (r <= 0)
return r;
164 fprintf(stderr,
"%s: Failed to read challenge.\n",
169 fr_hmac_md5(challenge, (uint8_t
const *) secret, strlen(secret),
170 challenge,
sizeof(challenge));
173 if (r <= 0)
return r;
197 if (r <= 0)
return r;
203 fprintf(stdout,
"%s", buffer);
207 fprintf(stderr,
"ERROR: %s", buffer);
213 memcpy(&status, buffer,
sizeof(status));
214 status = ntohl(status);
218 if (r < 4)
return -1;
220 memcpy(¬ify, buffer,
sizeof(notify));
221 notify = ntohl(notify);
229 fprintf(stderr,
"Unexpected response\n");
242 char *buffer,
size_t bufsize)
247 fprintf(stdout,
"%s\n", command);
254 if (r <= 0)
return r;
259 static int do_connect(
int *out,
char const *file,
char const *server)
283 if (errno == ENOENT) {
284 fprintf(stderr,
"Perhaps you need to run the commands:");
285 fprintf(stderr,
"\tcd /etc/raddb\n");
286 fprintf(stderr,
"\tln -s sites-available/control-socket "
287 "sites-enabled/control-socket\n");
288 fprintf(stderr,
"and then re-start the server?\n");
304 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (
void *)&set,
sizeof(
int));
312 magic = htonl(magic);
313 memcpy(buffer, &magic,
sizeof(magic));
314 memset(buffer +
sizeof(magic), 0,
sizeof(magic));
319 fprintf(stderr,
"%s: Error in socket: %s\n",
326 if (r <= 0)
goto do_close;
329 (memcmp(buffer, buffer + 8, 8) != 0)) {
330 fprintf(stderr,
"%s: Incompatible versions\n", progname);
335 if (server && secret) {
337 if (r <= 0)
goto do_close;
345 #define MAX_COMMANDS (4)
347 int main(
int argc,
char **argv)
354 char const *file = NULL;
355 char const *
name =
"radiusd";
356 char *p, buffer[65536];
357 char const *input_file = NULL;
358 FILE *inputfp = stdin;
359 char const *server = NULL;
366 int num_commands = -1;
368 int exit_status = EXIT_SUCCESS;
377 talloc_set_log_stderr();
379 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
385 while ((argval = getopt(argc, argv,
"d:D:hi:e:Ef:n:qs:S")) != EOF) {
389 fprintf(stderr,
"%s: -d and -f cannot be used together.\n", progname);
393 fprintf(stderr,
"%s: -d and -s cannot be used together.\n", progname);
406 fprintf(stderr,
"%s: Too many '-e'\n",
411 commands[num_commands] = optarg;
428 if (strcmp(optarg,
"-") != 0) {
444 fprintf(stderr,
"%s: -s and -f cannot be used together.\n", progname);
470 char const *uid_name = NULL;
471 char const *gid_name = NULL;
477 snprintf(buffer,
sizeof(buffer),
"%s/%s.conf", radius_dir, name);
497 fprintf(stderr,
"%s: Errors reading or parsing %s\n", progname, buffer);
513 if (!value)
continue;
515 if (strcmp(value,
"control") != 0)
continue;
523 fprintf(stderr,
"%s: Failed parsing listen section 'socket'\n", progname);
528 fprintf(stderr,
"%s: No path given for socket\n", progname);
543 fprintf(stderr,
"%s: Failed parsing listen section 'uid'\n", progname);
547 if (!uid_name)
break;
549 pwd = getpwnam(uid_name);
551 fprintf(stderr,
"%s: Failed getting UID for user %s: %s\n", progname, uid_name, strerror(errno));
555 if (uid != pwd->pw_uid)
continue;
560 fprintf(stderr,
"%s: Failed parsing listen section 'gid'\n", progname);
564 if (!gid_name)
break;
566 grp = getgrnam(gid_name);
568 fprintf(stderr,
"%s: Failed getting GID for group %s: %s\n", progname, gid_name, strerror(errno));
572 if (gid != grp->gr_gid)
continue;
578 fprintf(stderr,
"%s: Could not find control socket in %s\n", progname, buffer);
584 inputfp = fopen(input_file,
"r");
586 fprintf(stderr,
"%s: Failed opening %s: %s\n", progname, input_file,
fr_syserror(errno));
591 if (!file && !server) {
592 fprintf(stderr,
"%s: Must use one of '-d' or '-f' or '-s'\n",
600 if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet =
true;
604 #ifdef USE_READLINE_HISTORY
607 rl_bind_key(
'\t', rl_insert);
614 signal(SIGPIPE, SIG_IGN);
616 if (
do_connect(&sockfd, file, server) < 0) exit(1);
621 if (num_commands >= 0) {
624 for (i = 0; i <= num_commands; i++) {
625 len =
run_command(sockfd, commands[i], buffer,
sizeof(buffer));
626 if (len < 0) exit(1);
639 printf(
"%s - FreeRADIUS Server administration tool.\n", radmin_version);
640 printf(
"Copyright (C) 2008-2015 The FreeRADIUS server project and contributors.\n");
641 printf(
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
642 printf(
"PARTICULAR PURPOSE.\n");
643 printf(
"You may redistribute copies of FreeRADIUS under the terms of the\n");
644 printf(
"GNU General Public License v2.\n");
661 line = readline(
"radmin> ");
670 #ifdef USE_READLINE_HISTORY
676 line = fgets(buffer,
sizeof(buffer), inputfp);
679 p = strchr(buffer,
'\n');
681 fprintf(stderr,
"%s: Input line too long\n",
691 for (p = line; *p !=
'\0'; p++) {
714 for (p = line; *p !=
'\0'; p++) {
715 if ((p[0] ==
'\r') ||
723 if (strcmp(line,
"reconnect") == 0) {
724 if (
do_connect(&sockfd, file, server) < 0) exit(1);
729 if (memcmp(line,
"secret ", 7) == 0) {
741 if ((strcmp(line,
"exit") == 0) ||
742 (strcmp(line,
"quit") == 0)) {
746 if (server && !secret) {
747 fprintf(stderr,
"ERROR: You must enter 'secret <SECRET>' before running any commands\n");
754 len =
run_command(sockfd, line, buffer,
sizeof(buffer));
756 if (!quiet) fprintf(stderr,
"... reconnecting ...\n");
763 if (retries < 2)
goto retry;
765 fprintf(stderr,
"Failed to connect to server\n");
772 exit_status = EXIT_FAILURE;
776 fprintf(stdout,
"\n");
778 if (inputfp != stdin) fclose(inputfp);
static ssize_t flush_channels(int sockfd, char *buffer, size_t bufsize)
static char const * dict_dir
int cf_pair_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt, FR_TOKEN dflt_quote)
Parses a CONF_PAIR into a C data type, with a default value.
static char const * radius_dir
Path to raddb directory.
int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Main server configuration.
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
int fr_socket_client_unix(char const *path, bool async)
int cf_file_read(CONF_SECTION *cs, char const *file)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
int main(int argc, char **argv)
#define rad_waitpid(a, b)
ssize_t fr_channel_read(int fd, fr_channel_type_t *pchannel, void *buffer, size_t buflen)
static char const * progname
static int client_socket(char const *server)
CONF_PAIR * cf_pair_find(CONF_SECTION const *, char const *name)
char const * cf_pair_value(CONF_PAIR const *pair)
int fr_fault_setup(char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Vendors and attribute names.
main_config_t main_config
Main server configuration.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
static void NEVER_RETURNS usage(int status)
void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len, uint8_t const *key, size_t key_len) CC_BOUNDED(__minbytes__
static int do_connect(int *out, char const *file, char const *server)
CONF_SECTION * cf_subsection_find_next(CONF_SECTION const *section, CONF_SECTION const *subsection, char const *name1)
void void fr_perror(char const *,...) CC_HINT(format(printf
static char const * secret
#define RADIUS_DICTIONARY
Configuration AVP similar to a VALUE_PAIR.
static ssize_t run_command(int sockfd, char const *command, char *buffer, size_t bufsize)
#define FR_ITEM_POINTER(_t, _p)
ssize_t fr_channel_write(int fd, fr_channel_type_t channel, void const *buffer, size_t buflen)
CONF_SECTION * cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
Allocate a CONF_SECTION.
static ssize_t do_challenge(int sockfd)
size_t strlcpy(char *dst, char const *src, size_t siz)
String of printable characters.
int fr_dict_init(TALLOC_CTX *ctx, fr_dict_t **out, char const *dir, char const *fn, char const *name)
(re)initialize a protocol dictionary
#define RADIUSD_MAGIC_NUMBER
static char const * radmin_version