The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radmin.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: cb4df2c02bb89097002bf9bd894e468858cf3a91 $
19 *
20 * @file src/listen/control/radmin.c
21 * @brief Control a running radiusd process.
22 *
23 * @copyright 2012-2016 The FreeRADIUS server project
24 * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 * @copyright 2012 Alan DeKok (aland@deployingradius.com)
26 */
27RCSID("$Id: cb4df2c02bb89097002bf9bd894e468858cf3a91 $")
28
29#include <assert.h>
30
31#include <pwd.h>
32#include <grp.h>
33#include <fcntl.h>
34
35#ifdef HAVE_GETOPT_H
36# include <getopt.h>
37#endif
38
39#ifdef HAVE_SYS_STAT_H
40# include <sys/stat.h>
41#endif
42
43#ifdef HAVE_LIBREADLINE
44
45# include <stdio.h>
46
47DIAG_OFF(strict-prototypes)
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)
54#endif /* !defined(HAVE_READLINE_H) */
55DIAG_ON(strict-prototypes)
56
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)
62# include <history.h>
63# define USE_READLINE_HISTORY (1)
64#endif /* defined(HAVE_READLINE_HISTORY_H) */
65#endif /* HAVE_READLINE_HISTORY */
66#endif /* HAVE_LIBREADLINE */
67
68#define LOG_PREFIX "radmin"
69
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>
74
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
80#ifdef USE_READLINE_HISTORY
81#ifndef READLINE_MAX_HISTORY_LINES
82# define READLINE_MAX_HISTORY_LINES 1000
83#endif
84#endif
85
86#include "conduit.h"
87
88/*
89 * For configuration file stuff.
90 */
91static char const *progname = "radmin";
92static char const *radmin_version = RADIUSD_VERSION_BUILD("radmin");
93
94typedef enum {
95 RADMIN_CONN_NONE = 0, //!< Don't know, never connected.
96 RADMIN_CONN_UNIX, //!< Connect via unix socket.
97 RADMIN_CONN_TCP //!< Connect via TCP.
99
100/** A connection to a server
101 *
102 */
103typedef struct {
104 fr_event_list_t *event_list; //!< Event list this fd is serviced by.
105 int fd; //!< Control socket descriptor.
106
107 char *last_command; //!< Last command we executed on this connection.
108 char *server; //!< Path or FQDN of server we're connected to.
109 char *secret; //!< We use to authenticate ourselves to the server.
110
111 bool nonblock; //!< Whether this connection should operate in
112 //!< non-blocking mode.
113 bool connected; //!< Whether this connection is currently connected.
115 radmin_conn_type_t type; //!< Type of connection.
117
118/** Radmin state
119 *
120 * Many of the readline functions don't take callbacks, so we need
121 * to use a global structure to communicate radmin state.
122 */
123typedef struct {
124 fr_event_list_t *event_list; //!< Our main event list.
125
126 radmin_conn_t *active_conn; //!< Connection to remote entity.
128
129/** Main radmin state
130 *
131 */
132//static radmin_state_t state;
133
134static bool echo = false;
135static char const *secret = NULL;
136static bool unbuffered = false;
137static bool use_readline = true;
138
140 .dst = L_DST_NULL,
141 .colourise = false,
142 .timestamp = L_TIMESTAMP_ON,
143 .fd = -1,
144 .file = NULL,
145};
146static int sockfd = -1;
147static char io_buffer[65536];
148
149#ifdef USE_READLINE
150#define CMD_MAX_EXPANSIONS (128)
151static int radmin_num_expansions = 0;
152static char *radmin_expansions[CMD_MAX_EXPANSIONS] = {0};
153#endif
154
155#define MAX_STACK (64)
156static int stack_depth;
157static char cmd_buffer[65536];
158static char *stack[MAX_STACK];
159
160static fr_cmd_t *local_cmds = NULL;
161
163static fr_dict_t const *dict_radius;
164
166 { .out = &dict_freeradius, .proto = "freeradius" },
167 { .out = &dict_radius, .proto = "radius" },
169};
170
173
175 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
176 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
177
179};
180
181
182static NEVER_RETURNS void usage(int status)
183{
184 FILE *output = status ? stderr : stdout;
185 fprintf(output, "Usage: %s [ args ]\n", progname);
186 fprintf(output, " -d <confdir> Configuration file directory. (defaults to " CONFDIR ").");
187 fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
188 fprintf(output, " -e command Execute 'command' and then exit.\n");
189 fprintf(output, " -E Echo commands as they are being executed.\n");
190 fprintf(output, " -f socket_file Open socket_file directly, without reading radius.conf\n");
191 fprintf(output, " -h Print usage help information.\n");
192 fprintf(output, " -i input_file Read commands from 'input_file'.\n");
193 fprintf(output, " -l <log_file> Commands which are executed will be written to this file.\n");
194 fprintf(output, " -n name Read ${confdir}/name.conf instead of ${confdir}/radiusd.conf\n");
195 fprintf(output, " -q Reduce output verbosity\n");
196 fprintf(output, " -s <server> When '-d' is specified, look in the named virtual server for\n");
197 fprintf(output, " the control socket filename.\n");
198 fprintf(output, " Otherwise start a TCP connection to the named server and port.\n");
199 fprintf(output, " -S <secret> Use argument as shared secret for authentication to the server.\n");
200 fprintf(output, " Note that local users may be able to read the secret via 'ps'!\n");
201 fprintf(output, " -x Increase output verbosity\n");
202 fr_exit_now(status);
203}
204
205/*
206 * Create the client socket.
207 *
208 * @todo - use the BIO code. But this means lots of changes to convert bare strings into the complex
209 * data structures needed by the BIO code. That functionality properly belongs in a BIO FD helper
210 * function.
211 */
212static int client_socket(char const *server)
213{
214 int fd;
215 uint16_t port;
216 fr_ipaddr_t ipaddr;
217 char *p, buffer[1024];
218
219 strlcpy(buffer, server, sizeof(buffer));
220
221 p = strchr(buffer, ':');
222 if (!p) {
223 port = FR_RADMIN_PORT;
224 } else {
225 port = atoi(p + 1);
226 *p = '\0';
227 }
228
229 if (fr_inet_hton(&ipaddr, AF_INET, buffer, false) < 0) {
230 fprintf(stderr, "%s: Failed looking up host %s: %s\n",
231 progname, buffer, fr_syserror(errno));
232 fr_exit_now(EXIT_FAILURE);
233 }
234
235 fd = fr_socket_client_tcp(NULL, NULL, &ipaddr, port, false);
236 if (fd < 0) {
237 fprintf(stderr, "%s: Failed opening socket %s: %s\n",
238 progname, server, fr_syserror(errno));
239 fr_exit_now(EXIT_FAILURE);
240 }
241
242 return fd;
243}
244
245static ssize_t do_challenge(int fd)
246{
247 ssize_t r;
248 fr_conduit_type_t conduit;
249 uint8_t hmac[16];
250 uint8_t challenge[16];
251
252 challenge[0] = 0x00;
253
254 /*
255 * When connecting over a socket, the server challenges us.
256 */
257 r = fr_conduit_read(fd, &conduit, challenge, sizeof(challenge));
258 if (r <= 0) return r;
259
260 if ((r != 16) || (conduit != FR_CONDUIT_AUTH_CHALLENGE)) {
261 fprintf(stderr, "%s: Failed to read challenge.\n",
262 progname);
263 fr_exit_now(EXIT_FAILURE);
264 }
265
266 if (!secret) return -1;
267
268 fr_hmac_md5(hmac, (uint8_t const *) secret, strlen(secret),
269 challenge, sizeof(challenge));
270
271 r = fr_conduit_write(fd, FR_CONDUIT_AUTH_RESPONSE, hmac, sizeof(hmac));
272 if (r <= 0) return r;
273
274 /*
275 * If the server doesn't like us, it just closes the
276 * socket. So we don't look for an ACK.
277 */
278
279 return r;
280}
281
282
283/*
284 * Returns -1 on failure. 0 on connection failed. +1 on OK.
285 */
286static ssize_t flush_conduits(int fd, char *buffer, size_t bufsize)
287{
288 ssize_t r;
289#ifdef USE_READLINE
290 char *p, *str;
291#endif
292 uint32_t status;
293 fr_conduit_type_t conduit;
294
295 while (true) {
296 uint32_t notify;
297
298 r = fr_conduit_read(fd, &conduit, buffer, bufsize - 1);
299 if (r <= 0) return r;
300
301 buffer[r] = '\0'; /* for C strings */
302
303 switch (conduit) {
305 fprintf(stdout, "%s", buffer);
306 break;
307
309 fprintf(stderr, "ERROR: %s\n", buffer);
310 break;
311
313 if (r < 4) return 1;
314
315 memcpy(&status, buffer, sizeof(status));
316 status = ntohl(status);
317 return status;
318
320 if (r < 4) return -1;
321
322 memcpy(&notify, buffer, sizeof(notify));
323 notify = ntohl(notify);
324
325 if (notify == FR_NOTIFY_UNBUFFERED) unbuffered = true;
326 if (notify == FR_NOTIFY_BUFFERED) unbuffered = false;
327
328 break;
329
330#ifdef USE_READLINE
332 str = buffer;
333
334 for (p = buffer; p < (buffer + r); p++) {
335 if (*p == '\n') {
336 size_t len;
337
338 len = p - str;
339
340 MEM(radmin_expansions[radmin_num_expansions] = malloc(len + 1));
341 memcpy(radmin_expansions[radmin_num_expansions], str, len);
342 radmin_expansions[radmin_num_expansions][len] = '\0';
343 radmin_num_expansions++;
344
345 str = p + 1;
346 }
347
348 if (radmin_num_expansions >= CMD_MAX_EXPANSIONS) break;
349 }
350 break;
351#endif
352
353 default:
354 fprintf(stderr, "Unexpected response %02x\n", conduit);
355 return -1;
356 }
357 }
358
359 /* never gets here */
360}
361
362
363/*
364 * Returns -1 on failure. 0 on connection failed. +1 on OK.
365 */
366static ssize_t run_command(int fd, char const *command,
367 char *buffer, size_t bufsize)
368{
369 ssize_t r;
370 char const *p = command;
371
373 if (!*p) return FR_CONDUIT_SUCCESS;
374
375 if (echo) {
376 fprintf(stdout, "%s\n", command);
377 }
378
379 /*
380 * Write the text to the socket.
381 */
382 r = fr_conduit_write(fd, FR_CONDUIT_STDIN, p, strlen(p));
383 if (r <= 0) return r;
384
385 return flush_conduits(fd, buffer, bufsize);
386}
387
388static int do_connect(int *out, char const *file, char const *server)
389{
390 int fd;
391 ssize_t r;
392 fr_conduit_type_t conduit;
393 char buffer[65536];
394
395 uint32_t magic;
396
397 /*
398 * Close stale file descriptors
399 */
400 if (*out != -1) {
401 close(*out);
402 *out = -1;
403 }
404
405 if (file) {
406 /*
407 * FIXME: Get destination from command line, if possible?
408 */
409 fd = fr_socket_client_unix(file, false);
410 if (fd < 0) {
411 fr_perror("radmin");
412 if (errno == ENOENT) {
413 fprintf(stderr, "Perhaps you need to run the commands:");
414 fprintf(stderr, "\tcd " CONFDIR "\n");
415 fprintf(stderr, "\tln -s sites-available/control-socket "
416 "sites-enabled/control-socket\n");
417 fprintf(stderr, "and then re-start the server?\n");
418 }
419 return -1;
420 }
421 } else {
422 fd = client_socket(server);
423 }
424
425 /*
426 * Only works for BSD, but Linux allows us
427 * to mask SIGPIPE, so that's fine.
428 */
429#ifdef SO_NOSIGPIPE
430 {
431 int set = 1;
432
433 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
434 }
435#endif
436
437 /*
438 * Set up the initial header data.
439 */
440 magic = FR_CONDUIT_MAGIC;
441 magic = htonl(magic);
442 memcpy(buffer, &magic, sizeof(magic));
443 memset(buffer + sizeof(magic), 0, sizeof(magic));
444
446 if (r <= 0) {
447 do_close:
448 fprintf(stderr, "%s: Error in socket: %s\n",
449 progname, fr_syserror(errno));
450 close(fd);
451 return -1;
452 }
453
454 r = fr_conduit_read(fd, &conduit, buffer + 8, 8);
455 if (r <= 0) goto do_close;
456
457 if ((r != 8) || (conduit != FR_CONDUIT_INIT_ACK) ||
458 (memcmp(buffer, buffer + 8, 8) != 0)) {
459 fprintf(stderr, "%s: Incompatible versions\n", progname);
460 close(fd);
461 return -1;
462 }
463
464 if (secret) {
465 r = do_challenge(fd);
466 if (r <= 0) goto do_close;
467 }
468
469 *out = fd;
470
471 return 0;
472}
473
474
475static char readline_buffer[1024];
476
477/*
478 * Wrapper around readline which does the "right thing" depending
479 * on whether we're reading from a file or not. It also ignores
480 * blank lines and comments, which the main readline() API
481 * doesn't do.
482 */
483static char *my_readline(char const *prompt, FILE *fp_in, FILE *fp_out)
484{
485 char *line, *p;
486
487#ifdef USE_READLINE
488 if (use_readline) return readline(prompt);
489#endif
490
491 if (prompt && *prompt) puts(prompt);
492 fflush(fp_out);
493
494 line = fgets((char *) readline_buffer, sizeof(readline_buffer), fp_in);
495 if (!line) return NULL;
496
497 p = strchr(line, '\n');
498 if (!p) {
499 fprintf(stderr, "Input line too long\n");
500 return NULL;
501 }
502 *p = '\0';
503
505
506 /*
507 * Comments: keep going.
508 */
509 if (line[0] == '#') {
510 *line = '\0';
511 return line;
512 }
513
514 /*
515 * Strip off CR / LF
516 */
517 for (p = line; *p != '\0'; p++) {
518 if ((p[0] == '\r') ||
519 (p[0] == '\n')) {
520 p[0] = '\0';
521 break;
522 }
523 }
524
525 return line;
526}
527
528#ifdef USE_READLINE
529static void radmin_free(char *line)
530{
531 /*
532 * Was read from stdin, so "line" == "readline_buffer"
533 */
534 if (!use_readline) return;
535
536 free(line);
537}
538#else
539#define radmin_free(_x)
540#endif
541
542/*
543 * Copies the (possible partial) command to the command buffer,
544 * so that we can send the full command over to the server.
545 */
546static ssize_t cmd_copy(char const *cmd)
547{
548 size_t len;
549 char *p = stack[stack_depth];
550
551 if (stack_depth > 0) *(p++) = ' ';
552
553 /*
554 * No input, allow a trailing space so that tab
555 * completion works.
556 */
557 if (!*cmd) {
558 return p - cmd_buffer;
559 }
560
561 len = strlcpy(p, cmd, cmd_buffer + sizeof(cmd_buffer) - p);
562 if ((p + len) >= (cmd_buffer + sizeof(cmd_buffer))) {
563 fprintf(stderr, "Command too long\n");
564 return -1;
565 }
566
567 /*
568 * Trash trailing spaces.
569 */
570 for (p += len;
571 p > cmd_buffer;
572 p--) {
573 if (!isspace((uint8_t) p[-1])) break;
574 p[-1] = '\0';
575 }
576
577 return p - cmd_buffer;
578}
579
580#ifdef USE_READLINE
581static int radmin_help(UNUSED int count, UNUSED int key)
582{
583 ssize_t len;
584
585 printf("\n");
586
587 len = cmd_copy(rl_line_buffer);
588 if (len < 0) return 0;
589
590 /*
591 * Special-case help for local commands.
592 */
593 if ((len >= 5) && strncmp(cmd_buffer, "local", 5) == 0) {
595 rl_on_new_line();
596 return 0;
597 }
598
599 if (len > 0) {
601 } else {
602 /*
603 * Don't write zero bytes to the other side...
604 */
605 (void) fr_conduit_write(sockfd, FR_CONDUIT_HELP, " ", 1);
606 }
607
608 (void) flush_conduits(sockfd, io_buffer, sizeof(io_buffer));
609
610 rl_on_new_line();
611 return 0;
612}
613
614static char *
615radmin_expansion_walk(UNUSED const char *text, int state)
616{
617 static int current;
618 char *name;
619
620 if (!state) {
621 current = 0;
622 }
623
624 /*
625 * fr_command_completions() takes care of comparing things to
626 * suppress expansions which don't match "text"
627 */
628 if (current >= radmin_num_expansions) return NULL;
629
630 name = radmin_expansions[current];
631
632 radmin_expansions[current++] = NULL;
633
634 return name;
635}
636
637static char **
638radmin_completion(const char *text, int start, UNUSED int end)
639{
640 ssize_t len;
641
642 rl_attempted_completion_over = 1;
643
644 radmin_num_expansions = 0;
645
646 len = cmd_copy(rl_line_buffer);
647 if (len < 0) return NULL;
648
649 /*
650 * Handle local commands specially.
651 */
652 if (strncmp(cmd_buffer, "local", 5) == 0) {
653 int num;
654 char **expansions = &radmin_expansions[0];
655 char const **expansions_const;
656
657 memcpy(&expansions_const, &expansions, sizeof(expansions)); /* const issues */
659 CMD_MAX_EXPANSIONS, expansions_const);
660 if (num <= 0) return NULL;
661
662 radmin_num_expansions = num;
663 return rl_completion_matches(text, radmin_expansion_walk);
664 }
665
666 start += len;
667
668 if (start > 65535) return NULL;
669
670 io_buffer[0] = (start >> 8) & 0xff;
671 io_buffer[1] = start & 0xff;
672
673 /*
674 * Note that "text" is the PARTIAL thing we're trying to complete.
675 * And "start" is the OFFSET from rl_line_buffer where we want to
676 * do the completion. It's all rather idiotic.
677 */
678 memcpy(io_buffer + 2, cmd_buffer, len);
679
681
682 (void) flush_conduits(sockfd, io_buffer, sizeof(io_buffer));
683
684 return rl_completion_matches(text, radmin_expansion_walk);
685}
686
687#endif
688
689#ifndef USE_READLINE_HISTORY
690# define add_history(line)
691# define write_history(history_file)
692#endif
693
694/*
695 * See if there is a control socket in the given virtual server.
696 */
697static int check_server(CONF_SECTION *subcs, uid_t uid, gid_t gid, char const **file_p, char const **server_p)
698{
699 int rcode;
700 char const *value, *file = NULL;
701 CONF_SECTION *cs;
702 CONF_PAIR *cp;
703 char const *uid_name = NULL;
704 char const *gid_name = NULL;
705 char const *server;
706 struct passwd *pwd;
707 struct group *grp;
708
709 cp = cf_pair_find(subcs, "namespace");
710 if (!cp) return 0;
711
712 value = cf_pair_value(cp);
713 if (!value) return 0;
714
715 if (strcmp(value, "control") != 0) return 0;
716
717 server = cf_section_name2(subcs);
718 *server_p = server; /* need this for error messages */
719
720 /* listen {} */
721 cs = cf_section_find(subcs, "listen", NULL);
722 if (!cs) {
723 fprintf(stderr, "%s: Failed parsing 'listen{}' section in 'server %s {...}'\n", progname, server);
724 return -1;
725 }
726
727 /* transport = <transport> */
728 cp = cf_pair_find(cs, "transport");
729 if (!cp) return 0;
730
731 value = cf_pair_value(cp);
732 if (!value) return 0;
733
734 /* <transport> { ... } */
735 subcs = cf_section_find(cs, value, NULL);
736 if (!subcs) {
737 fprintf(stderr, "%s: Failed parsing the '%s {}' section in 'server %s {...}'\n",
738 progname, value, server);
739 return -1;
740 }
741
742 /*
743 * Now find the socket name (sigh)
744 */
745 rcode = cf_pair_parse(NULL, subcs, "filename",
747 if (rcode < 0) {
748 fprintf(stderr, "%s: Failed parsing listen section 'socket'\n", progname);
749 return -1;
750 }
751
752 if (!file) {
753 fprintf(stderr, "%s: No path given for socket\n", progname);
754 return -1;
755 }
756
757 *file_p = file;
758
759 /*
760 * If we're root, just use the first one we find
761 */
762 if (uid == 0) return 1;
763
764 /*
765 * Check UID and GID.
766 */
767 rcode = cf_pair_parse(NULL, subcs, "uid",
769 if (rcode < 0) {
770 fprintf(stderr, "%s: Failed parsing listen section 'uid'\n", progname);
771 return -1;
772 }
773
774 if (!uid_name || !*uid_name) return 1;
775
776 pwd = getpwnam(uid_name);
777 if (!pwd) {
778 fprintf(stderr, "%s: Failed getting UID for user %s: %s\n", progname, uid_name,
779 fr_syserror(errno));
780 return -1;
781 }
782
783 if (uid != pwd->pw_uid) return 0;
784
785 rcode = cf_pair_parse(NULL, subcs, "gid",
787 if (rcode < 0) {
788 fprintf(stderr, "%s: Failed parsing listen section 'gid'\n", progname);
789 return -1;
790 }
791
792 if (!gid_name || !*gid_name) return 1;
793
794 grp = getgrnam(gid_name);
795 if (!grp) {
796 fprintf(stderr, "%s: Failed resolving gid of group %s: %s\n",
797 progname, gid_name, fr_syserror(errno));
798 return -1;
799 }
800
801 if (gid != grp->gr_gid) return 0;
802
803 return 1;
804}
805
806static int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
807{
808 fprintf(fp, "We're testing stuff!\n");
809
810 return 0;
811}
812
813/*
814 * Local radmin commands
815 */
817 {
818 .parent = "local",
819 .name = "test",
820 .func = cmd_test,
821 .help = "Test stuff",
822 .read_only = true
823 },
824
826};
827
829
830static int local_command(char *line)
831{
832 int argc, ret;
833
835 if (argc < 0) {
836 fr_perror("Failed parsing local command");
837 return -1;
838 }
839
840 if (!local_info.runnable) {
841 return 0;
842 }
843
844 ret = fr_command_run(stderr, stdout, &local_info, false);
845 fflush(stdout);
846 fflush(stderr);
847
848 /*
849 * reset "info" to be a top-level context again.
850 */
851 (void) fr_command_clear(0, &local_info);
852
853 if (ret < 0) return ret;
854
855 return 1;
856
857}
858
859
860#define MAX_COMMANDS (256)
861
862int main(int argc, char **argv)
863{
864 int c;
865 bool quiet = false;
866 char *line = NULL;
867 ssize_t result;
868 char const *file = NULL;
869 char const *name = "radiusd";
870 char const *input_file = NULL;
871 FILE *inputfp = stdin;
872 char const *server = NULL;
873 fr_dict_t *dict = NULL;
874
875 char const *confdir = RADIUS_DIR;
876 char const *dict_dir = DICTDIR;
877#ifdef USE_READLINE_HISTORY
878 char history_file[PATH_MAX];
879#endif
880
881 TALLOC_CTX *autofree;
882
883 char *commands[MAX_COMMANDS];
884 int num_commands = 0;
885
886 int exit_status = EXIT_FAILURE;
887
888 char const *prompt = "radmin> ";
889 char prompt_buffer[1024];
890
891 /*
892 * Must be called first, so the handler is called last
893 */
895
897
898#ifndef NDEBUG
899 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
900 fr_perror("radmin");
901 fr_exit_now(EXIT_FAILURE);
902 }
903#endif
904
905 talloc_set_log_stderr();
906
907 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
908 progname = argv[0];
909 } else {
910 progname++;
911 }
912
914 secret = NULL;
915
916 while ((c = getopt(argc, argv, "d:D:hi:e:Ef:n:qs:S:x")) != -1) switch (c) {
917 case 'd':
918 confdir = optarg;
919 break;
920
921 case 'D':
922 dict_dir = optarg;
923 break;
924
925 case 'e':
926 if (num_commands >= MAX_COMMANDS) {
927 fprintf(stderr, "%s: Too many '-e'\n", progname);
928 fr_exit_now(EXIT_FAILURE);
929 }
930
931 commands[num_commands++] = optarg;
932 break;
933
934 case 'E':
935 echo = true;
936 break;
937
938 case 'f':
939 confdir = NULL;
940 file = optarg;
941 break;
942
943 default:
944 case 'h':
945 usage(EXIT_SUCCESS); /* never returns */
946
947 case 'i':
948 /*
949 * optarg check is to quiet clang scan
950 */
951 if (optarg && (strcmp(optarg, "-") != 0)) input_file = optarg;
952 quiet = true;
953 break;
954
955 case 'l':
956 radmin_log.file = optarg;
957 break;
958
959 case 'n':
960 name = optarg;
961 break;
962
963 case 'q':
964 quiet = true;
965 if (fr_debug_lvl > 0) fr_debug_lvl--;
966 break;
967
968 case 's':
969 server = optarg;
970 break;
971
972 case 'S':
973 secret = talloc_strdup(autofree, optarg);
974 break;
975
976 case 'x':
977 fr_debug_lvl++;
978 break;
979 }
980
981 /*
982 * Mismatch between the binary and the libraries it depends on
983 */
985 fr_perror("radmin");
986 fr_exit_now(EXIT_FAILURE);
987 }
988
989 if (confdir) {
990 int rcode;
991 uid_t uid;
992 gid_t gid;
993 CONF_SECTION *cs, *subcs;
994 CONF_PAIR *cp;
995
996 file = NULL; /* MUST read it from the conf_file now */
997
998 snprintf(io_buffer, sizeof(io_buffer), "%s/%s.conf", confdir, name);
999
1000 /*
1001 * Need to read in the dictionaries, else we may get
1002 * validation errors when we try and parse the config.
1003 */
1004 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1005 fail:
1006 fr_perror("radmin");
1007 goto done;
1008 }
1009
1010 if (fr_dict_internal_afrom_file(&dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) goto fail;
1011
1012 if (fr_dict_autoload(radmin_dict) < 0) goto fail;
1013
1014 if (fr_dict_attr_autoload(radmin_dict_attr) < 0) goto fail;
1015
1016 if (fr_dict_read(dict, confdir, FR_DICTIONARY_FILE) == -1) goto fail;
1017
1018 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1019 if (!cs) goto fail;
1020
1021 if ((cf_file_read(cs, io_buffer, true) < 0) || (cf_section_pass2(cs) < 0)) {
1022 fr_perror("radmin");
1023 fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, io_buffer);
1024 goto done;
1025 }
1026
1027 uid = getuid();
1028 gid = getgid();
1030
1031 /*
1032 * We are looking for: server whatever { namespace="control" ... }
1033 */
1034 if (server) {
1035 subcs = cf_section_find(cs, "server", server);
1036 if (!subcs) {
1037 fprintf(stderr, "%s: Could not find virtual server %s {}\n", progname, server);
1038 goto done;
1039 }
1040
1041 rcode = check_server(subcs, uid, gid, &file, &server);
1042 if (rcode < 0) goto done;
1043 if (rcode == 0) {
1044 fprintf(stderr, "%s: Could not find control socket virtual server %s { ... }\n", progname, server);
1045 goto done;
1046 }
1047
1048 } else {
1049 for (subcs = cf_section_find_next(cs, NULL, "server", CF_IDENT_ANY);
1050 subcs != NULL;
1051 subcs = cf_section_find_next(cs, subcs, "server", CF_IDENT_ANY)) {
1052 rcode = check_server(subcs, uid, gid, &file, &server);
1053 if (rcode < 0) goto done;
1054 if (rcode == 1) break;
1055 }
1056
1057 if (!file) {
1058 fprintf(stderr, "%s: Could not find 'namespace = control' in any virtual server\n", progname);
1059 goto done;
1060 }
1061 }
1062
1063 fr_assert(file);
1064
1065 /*
1066 * Log the commands we've run.
1067 */
1068 if (!radmin_log.file) {
1069 subcs = cf_section_find(cs, "log", NULL);
1070 if (subcs) {
1071 cp = cf_pair_find(subcs, "radmin");
1072 if (cp) {
1074
1075 if (!radmin_log.file) {
1076 fprintf(stderr, "%s: Invalid value for 'radmin' log destination\n", progname);
1077 goto done;
1078 }
1079 }
1080 }
1081 }
1082
1083 if (radmin_log.file) {
1084 radmin_log.fd = open(radmin_log.file, O_APPEND | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
1085 if (radmin_log.fd < 0) {
1086 fprintf(stderr, "%s: Failed opening %s: %s\n", progname, radmin_log.file, fr_syserror(errno));
1087 goto done;
1088 }
1089
1091 }
1092
1093 } else if (!file) {
1094 fprintf(stderr, "%s: No '-d <confdir' or '-f <socket_file>' specified.\n", progname);
1095 goto done;
1096
1097 } else if (server) {
1098 fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname);
1099 usage(EXIT_FAILURE);
1100 }
1101
1102 if (input_file) {
1103 inputfp = fopen(input_file, "r");
1104 if (!inputfp) {
1105 fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno));
1106 goto done;
1107 }
1108 }
1109
1110 /*
1111 * Check if stdin is a TTY only if input is from stdin
1112 */
1113 if (input_file || !isatty(STDIN_FILENO)) {
1114 use_readline = false;
1115 quiet = true;
1116 }
1117
1118 if (use_readline) {
1119#ifdef USE_READLINE_HISTORY
1120 char const *home = getenv("HOME");
1121
1122 if (home) {
1123 using_history();
1124 stifle_history(READLINE_MAX_HISTORY_LINES);
1125 snprintf(history_file, sizeof(history_file), "%s/%s", home, ".radmin_history");
1126 read_history(history_file);
1127 }
1128#endif
1129#ifdef USE_READLINE
1130 rl_attempted_completion_function = radmin_completion;
1131#endif
1132 } else {
1133 prompt = NULL;
1134 }
1135
1136 /*
1137 * Prevent SIGPIPEs from terminating the process
1138 */
1139 signal(SIGPIPE, SIG_IGN);
1140
1141 if (do_connect(&sockfd, file, server) < 0) goto done;
1142
1143 /*
1144 * Register local commands.
1145 */
1146 if (fr_command_add_multi(autofree, &local_cmds, NULL, NULL, cmd_table) < 0) {
1147 fprintf(stderr, "%s: Failed registering local commands: %s\n",
1149 goto done;
1150 }
1151
1153
1154 /*
1155 * Run commands from the command-line.
1156 */
1157 if (num_commands > 0) {
1158 int i;
1159
1160 for (i = 0; i < num_commands; i++) {
1161 result = run_command(sockfd, commands[i], io_buffer, sizeof(io_buffer));
1162 if (result < 0) goto done;
1163
1164 if (result == FR_CONDUIT_FAIL) goto done;
1165 }
1166
1167 if (unbuffered) {
1168 while (true) flush_conduits(sockfd, io_buffer, sizeof(io_buffer));
1169 }
1170
1171 /*
1172 * We're done all of the commands, exit now.
1173 */
1174 exit_status = EXIT_SUCCESS;
1175 goto done;
1176 }
1177
1178 if (!quiet) {
1179 printf("%s - FreeRADIUS Server administration tool.\n", radmin_version);
1180 printf("Copyright 2008-2026 The FreeRADIUS server project and contributors.\n");
1181 printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
1182 printf("PARTICULAR PURPOSE.\n");
1183 printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
1184 printf("GNU General Public License v2.\n");
1185 }
1186
1187 /*
1188 * FIXME: Do login?
1189 */
1190
1191#ifdef USE_READLINE
1192 (void) rl_bind_key('?', radmin_help);
1193#endif
1194
1195 stack_depth = 0;
1196 stack[0] = cmd_buffer;
1197
1198 while (1) {
1199 int retries;
1200 ssize_t len;
1201
1202 line = my_readline(prompt, inputfp, stdout);
1203
1204 if (!line) break;
1205
1206 if (!*line) goto next;
1207
1208 /*
1209 * Radmin supports a number of commands which are
1210 * valid in any context.
1211 */
1212 if (strcmp(line, "reconnect") == 0) {
1213 if (do_connect(&sockfd, file, server) < 0) {
1215 goto done;
1216 }
1217 goto next;
1218 }
1219
1220 if (!secret && !stack_depth && (strncmp(line, "secret ", 7) == 0)) {
1222 if (!secret) {
1224 goto done;
1225 }
1226
1227 if (do_challenge(sockfd) < 0) {
1229 goto done;
1230 }
1231
1232 /*
1233 * Don't add the secret to the history.
1234 */
1235 goto next;
1236 }
1237
1238 /*
1239 * Quit the program
1240 */
1241 if (strcmp(line, "quit") == 0) {
1243 break;
1244 }
1245
1246 /*
1247 * Exit the current context.
1248 */
1249 if (strcmp(line, "exit") == 0) {
1250 if (!stack_depth) {
1252 break;
1253 }
1254
1255 stack_depth--;
1256 *stack[stack_depth] = '\0';
1257
1258 if (stack_depth == 0) {
1259 prompt = "radmin> ";
1260 } else {
1261 snprintf(prompt_buffer, sizeof(prompt_buffer), "... %s> ",
1262 stack[stack_depth - 1]);
1263 prompt = prompt_buffer;
1264 }
1265
1266 goto next;
1267 }
1268
1269 /*
1270 * Radmin also supports local commands which
1271 * modifies it's behavior. These commands MUST
1272 */
1273 if (!stack_depth && (strncmp(line, "local", 5) == 0)) {
1274 if (!isspace((uint8_t) line[5])) {
1275 fprintf(stderr, "'local' commands MUST be specified all on one line");
1276 goto next;
1277 }
1278
1279 /*
1280 * Parse and run the local command.
1281 */
1283 goto next;
1284 }
1285
1286 /*
1287 * Any other input is sent to the server.
1288 */
1289 retries = 0;
1290
1291 /*
1292 * If required, log commands to a radmin log file.
1293 */
1294 if (radmin_log.dst == L_DST_FILES) {
1295 fr_log(&radmin_log, L_INFO, __FILE__, __LINE__, "%s", line);
1296 }
1297
1298 len = cmd_copy(line);
1299 if (len < 0) {
1301 goto done;
1302 }
1303
1304 retry:
1305
1306 result = run_command(sockfd, cmd_buffer, io_buffer, sizeof(io_buffer));
1307 if (result < 0) {
1308 if (!quiet) fprintf(stderr, "... reconnecting ...\n");
1309
1310 if (do_connect(&sockfd, file, server) < 0) {
1312 goto done;
1313 }
1314
1315 retries++;
1316 if (retries < 2) goto retry;
1317
1318 fprintf(stderr, "Failed to connect to server\n");
1320 goto done;
1321
1322 } else if (result == FR_CONDUIT_FAIL) {
1323 fprintf(stderr, "Failed running command\n");
1324 goto done;
1325
1326 } else if (result == FR_CONDUIT_PARTIAL) {
1327 char *p;
1328
1329 if (stack_depth >= (MAX_STACK - 1)) {
1330 fprintf(stderr, "Too many sub-contexts running command\n");
1332 goto done;
1333 }
1334
1335 /*
1336 * Point the stack to the last entry.
1337 */
1338 p = stack[stack_depth];
1339 p += strlen(p);
1340 stack_depth++;
1341 stack[stack_depth] = p;
1342
1343 snprintf(prompt_buffer, sizeof(prompt_buffer), "... %s> ",
1344 stack[stack_depth - 1]);
1345 prompt = prompt_buffer;
1346
1347 } else {
1348 /*
1349 * Add only successful commands to the history.
1350 *
1351 * Don't add exit / quit / secret / etc.
1352 */
1353 if (use_readline) {
1355 write_history(history_file);
1356 }
1357 }
1358
1359 /*
1360 * SUCCESS and PARTIAL end up here too.
1361 */
1362 next:
1364 }
1365 exit_status = EXIT_SUCCESS;
1366
1367done:
1368 if (fr_dict_autofree(radmin_dict) < 0) {
1369 fr_perror("radmin");
1370 exit_status = EXIT_FAILURE;
1371 }
1372
1373 fr_dict_free(&dict, __FILE__);
1374
1375 if (inputfp && (inputfp != stdin)) fclose(inputfp);
1376
1377 if (radmin_log.dst == L_DST_FILES) close(radmin_log.fd);
1378
1379 if (sockfd >= 0) close(sockfd);
1380
1381 if (!quiet && (exit_status == EXIT_SUCCESS)) fprintf(stdout, "\n");
1382
1383 /*
1384 * Ensure our atexit handlers run before any other
1385 * atexit handlers registered by third party libraries.
1386 */
1388
1389 return exit_status;
1390}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:159
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:285
static TALLOC_CTX * autofree
Definition fuzzer.c:44
static char * readline(char const *prompt)
Definition radmin.c:82
#define CMD_MAX_EXPANSIONS
Definition radmin.c:152
static fr_cmd_table_t cmd_table[]
Definition radmin.c:891
#define radmin_free(_x)
Definition radmin.c:136
static char readline_buffer[1024]
Definition radmin.c:80
#define RCSID(id)
Definition build.h:512
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:334
#define DIAG_ON(_x)
Definition build.h:487
#define UNUSED
Definition build.h:336
#define DIAG_OFF(_x)
Definition build.h:486
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition cf_file.c:3657
int cf_section_pass2(CONF_SECTION *cs)
Definition cf_file.c:970
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.
Definition cf_parse.c:785
#define FR_ITEM_POINTER(_type, _res_p)
Definition cf_parse.h:355
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:72
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1187
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1029
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1422
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.
Definition cf_util.c:1050
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1581
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:143
#define CF_IDENT_ANY
Definition cf_util.h:75
int fr_command_clear(int new_argc, fr_cmd_info_t *info)
Clear out any value boxes etc.
Definition command.c:2377
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[].
Definition command.c:2149
int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only)
Run a particular command.
Definition command.c:1481
void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info)
Initialize an fr_cmd_info_t structure.
Definition command.c:2405
int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
Do readline-style help completions.
Definition command.c:2796
int fr_command_complete(fr_cmd_t *head, char const *text, int start, int max_expansions, char const **expansions)
Do readline-style command completions.
Definition command.c:2653
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.
Definition command.c:993
char const * parent
e.g. "show module"
Definition command.h:52
bool runnable
is the command runnable?
Definition command.h:41
#define CMD_TABLE_END
Definition command.h:62
ssize_t fr_conduit_write(int fd, fr_conduit_type_t conduit, void const *out, size_t outlen)
Definition conduit.c:227
ssize_t fr_conduit_read(int fd, fr_conduit_type_t *pconduit, void *out, size_t outlen)
Definition conduit.c:145
API to provide distinct communication conduits for the radmin protocol.
#define FR_CONDUIT_MAGIC
Definition conduit.h:32
@ FR_CONDUIT_FAIL
Definition conduit.h:54
@ FR_CONDUIT_PARTIAL
Definition conduit.h:55
@ FR_CONDUIT_SUCCESS
Definition conduit.h:56
@ FR_NOTIFY_BUFFERED
Definition conduit.h:61
@ FR_NOTIFY_UNBUFFERED
Definition conduit.h:62
fr_conduit_type_t
Definition conduit.h:34
@ FR_CONDUIT_STDOUT
Definition conduit.h:36
@ FR_CONDUIT_AUTH_RESPONSE
Definition conduit.h:41
@ FR_CONDUIT_HELP
Definition conduit.h:43
@ FR_CONDUIT_NOTIFY
Definition conduit.h:42
@ FR_CONDUIT_STDIN
Definition conduit.h:35
@ FR_CONDUIT_STDERR
Definition conduit.h:37
@ FR_CONDUIT_CMD_STATUS
Definition conduit.h:38
@ FR_CONDUIT_INIT_ACK
Definition conduit.h:39
@ FR_CONDUIT_COMPLETE
Definition conduit.h:44
@ FR_CONDUIT_AUTH_CHALLENGE
Definition conduit.h:40
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1067
#define MEM(x)
Definition debug.h:46
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:236
static int retries
Definition dhcpclient.c:52
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
#define fr_dict_autofree(_to_free)
Definition dict.h:915
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
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_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4329
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4395
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
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.
Definition dict_util.c:4713
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Test enumeration values.
Definition dict_test.h:92
free(array)
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.
Definition hmac_md5.c:119
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Definition inet.c:255
IPv4/6 prefix.
Stores all information relating to an event list.
Definition event.c:377
int fr_debug_lvl
Definition log.c:40
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.
Definition log.c:577
@ L_DST_NULL
Discard log messages.
Definition log.h:80
@ L_DST_FILES
Log to a file on disk.
Definition log.h:76
@ L_TIMESTAMP_ON
Always log timestamps.
Definition log.h:87
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition log.h:67
@ L_INFO
Informational message.
Definition log.h:52
char * last_command
Last command we executed on this connection.
Definition radmin.c:107
static char io_buffer[65536]
Definition radmin.c:147
fr_event_list_t * event_list
Event list this fd is serviced by.
Definition radmin.c:104
static ssize_t do_challenge(int fd)
Definition radmin.c:245
static fr_cmd_t * local_cmds
Definition radmin.c:160
static int stack_depth
Definition radmin.c:156
static int client_socket(char const *server)
Definition radmin.c:212
static bool echo
Main radmin state.
Definition radmin.c:134
int main(int argc, char **argv)
Definition radmin.c:862
fr_event_list_t * event_list
Our main event list.
Definition radmin.c:124
static char * my_readline(char const *prompt, FILE *fp_in, FILE *fp_out)
Definition radmin.c:483
static int do_connect(int *out, char const *file, char const *server)
Definition radmin.c:388
static char const * radmin_version
Definition radmin.c:92
#define MAX_COMMANDS
Definition radmin.c:860
static fr_dict_t const * dict_freeradius
Definition radmin.c:162
radmin_conn_type_t type
Type of connection.
Definition radmin.c:115
static int local_command(char *line)
Definition radmin.c:830
static const fr_dict_attr_autoload_t radmin_dict_attr[]
Definition radmin.c:174
static ssize_t flush_conduits(int fd, char *buffer, size_t bufsize)
Definition radmin.c:286
static fr_dict_t const * dict_radius
Definition radmin.c:163
static fr_log_t radmin_log
Definition radmin.c:139
static const fr_dict_autoload_t radmin_dict[]
Definition radmin.c:165
static char const * secret
Definition radmin.c:135
bool nonblock
Whether this connection should operate in non-blocking mode.
Definition radmin.c:111
static bool use_readline
Definition radmin.c:137
#define write_history(history_file)
Definition radmin.c:691
radmin_conn_type_t
Definition radmin.c:94
@ RADMIN_CONN_UNIX
Connect via unix socket.
Definition radmin.c:96
@ RADMIN_CONN_TCP
Connect via TCP.
Definition radmin.c:97
@ RADMIN_CONN_NONE
Don't know, never connected.
Definition radmin.c:95
static ssize_t cmd_copy(char const *cmd)
Definition radmin.c:546
#define add_history(line)
Definition radmin.c:690
static fr_dict_attr_t const * attr_cleartext_password
Definition radmin.c:171
static char const * progname
Definition radmin.c:91
static fr_cmd_info_t local_info
Definition radmin.c:828
static fr_dict_attr_t const * attr_user_name
Definition radmin.c:172
int fd
Control socket descriptor.
Definition radmin.c:105
char * secret
We use to authenticate ourselves to the server.
Definition radmin.c:109
static char * stack[MAX_STACK]
Definition radmin.c:158
static int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
Definition radmin.c:806
bool connected
Whether this connection is currently connected.
Definition radmin.c:113
static bool unbuffered
Definition radmin.c:136
static int sockfd
Definition radmin.c:146
char * server
Path or FQDN of server we're connected to.
Definition radmin.c:108
static char cmd_buffer[65536]
Definition radmin.c:157
#define MAX_STACK
Definition radmin.c:155
static ssize_t run_command(int fd, char const *command, char *buffer, size_t bufsize)
Definition radmin.c:366
static int check_server(CONF_SECTION *subcs, uid_t uid, gid_t gid, char const **file_p, char const **server_p)
Definition radmin.c:697
fr_cs_buffer_t co
Definition radmin.c:114
radmin_conn_t * active_conn
Connection to remote entity.
Definition radmin.c:126
A connection to a server.
Definition radmin.c:103
Radmin state.
Definition radmin.c:123
unsigned short uint16_t
@ FR_TYPE_STRING
String of printable characters.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
#define FR_RADMIN_PORT
Definition radmin.h:39
static char const * name
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:36
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
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.
Definition socket.c:708
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
Definition socket.c:543
return count
Definition module.c:155
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
Definition log.h:93
fr_log_dst_t dst
Log destination.
Definition log.h:94
int fd
File descriptor to write messages to.
Definition log.h:109
char const * file
Path to log file.
Definition log.h:110
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:48
#define talloc_strdup(_ctx, _str)
Definition talloc.h:142
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
static fr_table_ptr_sorted_t commands[]
#define FR_DICTIONARY_FILE
Definition conf.h:7
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:8
#define RADIUS_DIR
Definition conf.h:3
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:732
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
static size_t char ** out
Definition value.h:1030