2 * radmin.c RADIUS Administration tool.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/radpaths.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
37 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
45 #ifdef HAVE_SYS_STAT_H
49 #ifdef HAVE_LIBREADLINE
51 #if defined(HAVE_READLINE_READLINE_H)
52 #include <readline/readline.h>
53 #define USE_READLINE (1)
54 #elif defined(HAVE_READLINE_H)
56 #define USE_READLINE (1)
57 #endif /* !defined(HAVE_READLINE_H) */
59 #endif /* HAVE_LIBREADLINE */
61 #ifdef HAVE_READLINE_HISTORY
62 #if defined(HAVE_READLINE_HISTORY_H)
63 #include <readline/history.h>
64 #define USE_READLINE_HISTORY (1)
65 #elif defined(HAVE_HISTORY_H)
67 #define USE_READLINE_HISTORY (1)
68 #endif /* defined(HAVE_READLINE_HISTORY_H) */
70 #endif /* HAVE_READLINE_HISTORY */
73 * For configuration file stuff.
75 char *radius_dir = RADDBDIR;
76 const char *progname = "radmin";
79 * The rest of this is because the conffile.c, etc. assume
80 * they're running inside of the server. And we don't (yet)
81 * have a "libfreeradius-server", or "libfreeradius-util".
84 struct main_config_t mainconfig;
85 char *request_log_file = NULL;
86 char *debug_log_file = NULL;
87 int radius_xlat(UNUSED char *out, UNUSED int outlen, UNUSED const char *fmt,
88 UNUSED REQUEST *request, UNUSED RADIUS_ESCAPE_STRING func)
92 int check_config = FALSE;
94 static FILE *outputfp = NULL;
95 static int echo = FALSE;
97 static int fr_domain_socket(const char *path)
103 struct sockaddr_un saremote;
106 if (len >= sizeof(saremote.sun_path)) {
107 fprintf(stderr, "%s: Path too long in filename\n", progname);
111 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
112 fprintf(stderr, "%s: Failed creating socket: %s\n",
113 progname, strerror(errno));
117 saremote.sun_family = AF_UNIX;
118 memcpy(saremote.sun_path, path, len + 1); /* SUN_LEN does strlen */
120 socklen = SUN_LEN(&saremote);
122 if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
126 fprintf(stderr, "%s: Failed connecting to %s: %s\n",
127 progname, path, strerror(errno));
130 * The file doesn't exist. Tell the user how to
133 if ((stat(path, &buf) < 0) &&
135 fprintf(stderr, " Perhaps you need to run the commands:\n\tcd /etc/raddb\n\tln -s sites-available/control-socket sites-enabled/control-socket\n and then re-start the server?\n");
145 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
146 fprintf(stderr, "%s: Failure getting socket flags: %s",
147 progname, strerror(errno));
153 if( fcntl(sockfd, F_SETFL, flags) < 0) {
154 fprintf(stderr, "%s: Failure setting socket flags: %s",
155 progname, strerror(errno));
165 static int usage(void)
167 printf("Usage: %s [ args ]\n", progname);
168 printf(" -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
169 printf(" -e command Execute 'command' and then exit.\n");
170 printf(" -E Echo commands as they are being executed.\n");
171 printf(" -f socket_file Open socket_file directly, without reading radius.conf\n");
172 printf(" -i input_file Read commands from 'input_file'.\n");
173 printf(" -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
174 printf(" -o output_file Write commands to 'output_file'.\n");
175 printf(" -q Quiet mode.\n");
180 static ssize_t run_command(int sockfd, const char *command,
181 char *buffer, size_t bufsize)
187 fprintf(outputfp, "%s\n", command);
191 * Write the text to the socket.
193 if (write(sockfd, command, strlen(command)) < 0) return -1;
194 if (write(sockfd, "\r\n", 2) < 0) return -1;
202 memset(buffer, 0, bufsize);
209 FD_SET(sockfd, &readfds);
211 rcode = select(sockfd + 1, &readfds, NULL, NULL, NULL);
213 if (errno == EINTR) continue;
215 fprintf(stderr, "%s: Failed selecting: %s\n",
216 progname, strerror(errno));
221 fprintf(stderr, "%s: Server closed the connection.\n",
227 len = recv(sockfd, buffer + size,
228 bufsize - size - 1, MSG_DONTWAIT);
231 * Read one byte at a time (ugh)
233 len = recv(sockfd, buffer + size, 1, 0);
237 * No data: keep looping
239 if ((errno == EAGAIN) || (errno == EINTR)) {
243 fprintf(stderr, "%s: Error reading socket: %s\n",
244 progname, strerror(errno));
247 if (len == 0) return 0; /* clean exit */
253 * There really is a better way of doing this.
255 p = strstr(buffer, "radmin> ");
262 if (p[-1] == '\n') p[-1] = '\0';
268 * Blank prompt. Go get another command.
270 if (!buffer[0]) return 1;
272 buffer[size] = '\0'; /* this is at least right */
277 #define MAX_COMMANDS (4)
279 int main(int argc, char **argv)
281 int argval, quiet = 0;
282 int done_license = 0;
287 const char *file = NULL;
288 const char *name = "radiusd";
289 char *p, buffer[65536];
290 const char *input_file = NULL;
291 FILE *inputfp = stdin;
292 const char *output_file = NULL;
294 char *commands[MAX_COMMANDS];
295 int num_commands = -1;
297 outputfp = stdout; /* stdout is not a constant value... */
299 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
304 while ((argval = getopt(argc, argv, "d:hi:e:Ef:n:o:q")) != EOF) {
308 fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname);
315 num_commands++; /* starts at -1 */
316 if (num_commands >= MAX_COMMANDS) {
317 fprintf(stderr, "%s: Too many '-e'\n",
321 commands[num_commands] = optarg;
339 if (strcmp(optarg, "-") != 0) {
350 if (strcmp(optarg, "-") != 0) {
351 output_file = optarg;
364 CONF_SECTION *cs, *subcs;
366 file = NULL; /* MUST read it from the conffile now */
368 snprintf(buffer, sizeof(buffer), "%s/%s.conf",
371 cs = cf_file_read(buffer);
373 fprintf(stderr, "%s: Errors reading %s\n",
379 while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) {
381 CONF_PAIR *cp = cf_pair_find(subcs, "type");
385 value = cf_pair_value(cp);
386 if (!value) continue;
388 if (strcmp(value, "control") != 0) continue;
391 * Now find the socket name (sigh)
393 rcode = cf_item_parse(subcs, "socket",
397 fprintf(stderr, "%s: Failed parsing listen section\n", progname);
402 fprintf(stderr, "%s: No path given for socket\n",
410 fprintf(stderr, "%s: Could not find control socket in %s\n",
417 inputfp = fopen(input_file, "r");
419 fprintf(stderr, "%s: Failed opening %s: %s\n",
420 progname, input_file, strerror(errno));
426 outputfp = fopen(output_file, "w");
428 fprintf(stderr, "%s: Failed creating %s: %s\n",
429 progname, output_file, strerror(errno));
435 * Check if stdin is a TTY only if input is from stdin
437 if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = 1;
441 #ifdef USE_READLINE_HISTORY
444 rl_bind_key('\t', rl_insert);
450 * FIXME: Get destination from command line, if possible?
452 sockfd = fr_domain_socket(file);
458 * Read initial magic && version information.
460 for (size = 0; size < 8; size += len) {
461 len = read(sockfd, buffer + size, 8 - size);
463 fprintf(stderr, "%s: Error reading initial data from socket: %s\n",
464 progname, strerror(errno));
469 memcpy(&magic, buffer, 4);
470 magic = ntohl(magic);
471 if (magic != 0xf7eead15) {
472 fprintf(stderr, "%s: Socket %s is not FreeRADIUS administration socket\n", progname, file);
476 memcpy(&magic, buffer + 4, 4);
477 magic = ntohl(magic);
479 fprintf(stderr, "%s: Socket version mismatch: Need 1, got %d\n",
487 if (num_commands >= 0) {
490 for (i = 0; i <= num_commands; i++) {
491 size = run_command(sockfd, commands[i],
492 buffer, sizeof(buffer));
493 if (size < 0) exit(1);
496 fputs(buffer, outputfp);
497 fprintf(outputfp, "\n");
504 if (!done_license && !quiet) {
505 printf("radmin " RADIUSD_VERSION " - FreeRADIUS Server administration tool.\n");
506 printf("Copyright (C) 2008-2011 The FreeRADIUS server project and contributors.\n");
507 printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
508 printf("PARTICULAR PURPOSE.\n");
509 printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
510 printf("GNU General Public License v2.\n");
527 line = readline("radmin> ");
536 #ifdef USE_READLINE_HISTORY
539 } else /* quiet, or no readline */
542 line = fgets(buffer, sizeof(buffer), inputfp);
545 p = strchr(buffer, '\n');
547 fprintf(stderr, "%s: Input line too long\n",
555 * Strip off leading spaces.
557 for (p = line; *p != '\0'; p++) {
573 * Comments: keep going.
580 for (p = line; *p != '\0'; p++) {
581 if ((p[0] == '\r') ||
589 if (strcmp(line, "reconnect") == 0) {
598 if ((strcmp(line, "exit") == 0) ||
599 (strcmp(line, "quit") == 0)) {
603 size = run_command(sockfd, line, buffer, sizeof(buffer));
604 if (size <= 0) break; /* error, or clean exit */
606 if (size == 1) continue; /* no output. */
608 fputs(buffer, outputfp);
610 fprintf(outputfp, "\n");
613 fprintf(outputfp, "\n");