2 * command.c Command socket processing.
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 #ifdef WITH_COMMAND_SOCKET
26 #include <freeradius-devel/parser.h>
27 #include <freeradius-devel/md5.h>
29 #ifdef HAVE_INTTYPES_H
36 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
40 #ifdef HAVE_SYS_STAT_H
52 typedef struct fr_command_table_t fr_command_table_t;
54 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
59 struct fr_command_table_t {
61 int mode; /* read/write */
63 fr_command_func_t func;
64 fr_command_table_t *table;
67 #define COMMAND_BUFFER_SIZE (1024)
69 typedef struct fr_cs_buffer_t {
74 char buffer[COMMAND_BUFFER_SIZE];
77 #define COMMAND_SOCKET_MAGIC (0xffdeadee)
78 typedef struct fr_command_socket_t {
81 char *copy; /* <sigh> */
86 char const *mode_name;
90 * The next few entries handle fake packets injected by
93 fr_ipaddr_t src_ipaddr; /* src_port is always 0 */
94 fr_ipaddr_t dst_ipaddr;
96 rad_listen_t *inject_listener;
97 RADCLIENT *inject_client;
100 } fr_command_socket_t;
102 static const CONF_PARSER command_config[] = {
103 { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, path), "${run_dir}/radiusd.sock" },
104 { "uid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, uid_name), NULL },
105 { "gid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, gid_name), NULL },
106 { "mode", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, mode_name), NULL },
108 { NULL, -1, 0, NULL, NULL } /* end the list */
111 static FR_NAME_NUMBER mode_names[] = {
113 { "read-only", FR_READ },
114 { "read-write", FR_READ | FR_WRITE },
115 { "rw", FR_READ | FR_WRITE },
119 extern const FR_NAME_NUMBER mod_rcode_table[];
121 #ifndef HAVE_GETPEEREID
122 static int getpeereid(int s, uid_t *euid, gid_t *egid)
128 socklen_t cl = sizeof(cr);
130 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
137 #endif /* SO_PEERCRED */
139 #endif /* HAVE_GETPEEREID */
142 static int fr_server_domain_socket(char const *path)
147 struct sockaddr_un salocal;
151 ERROR("No path provided, was NULL");
156 if (len >= sizeof(salocal.sun_path)) {
157 ERROR("Path too long in socket filename");
161 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
162 ERROR("Failed creating socket: %s",
167 memset(&salocal, 0, sizeof(salocal));
168 salocal.sun_family = AF_UNIX;
169 memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
171 socklen = SUN_LEN(&salocal);
176 if (stat(path, &buf) < 0) {
177 if (errno != ENOENT) {
178 ERROR("Failed to stat %s: %s",
179 path, fr_syserror(errno));
185 * FIXME: Check the enclosing directory?
187 } else { /* it exists */
188 if (!S_ISREG(buf.st_mode)
190 && !S_ISSOCK(buf.st_mode)
193 ERROR("Cannot turn %s into socket", path);
199 * Refuse to open sockets not owned by us.
201 if (buf.st_uid != geteuid()) {
202 ERROR("We do not own %s", path);
207 if (unlink(path) < 0) {
208 ERROR("Failed to delete %s: %s",
209 path, fr_syserror(errno));
215 if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
216 ERROR("Failed binding to %s: %s",
217 path, fr_syserror(errno));
223 * FIXME: There's a race condition here. But Linux
224 * doesn't seem to permit fchmod on domain sockets.
226 if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
227 ERROR("Failed setting permissions on %s: %s",
228 path, fr_syserror(errno));
233 if (listen(sockfd, 8) < 0) {
234 ERROR("Failed listening to %s: %s",
235 path, fr_syserror(errno));
244 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
245 ERROR("Failure getting socket flags: %s",
252 if( fcntl(sockfd, F_SETFL, flags) < 0) {
253 ERROR("Failure setting socket flags: %s",
265 static void command_close_socket(rad_listen_t *this)
267 this->status = RAD_LISTEN_STATUS_EOL;
270 * This removes the socket from the event fd, so no one
271 * will be calling us any more.
273 radius_update_listener(this);
276 static ssize_t CC_HINT(format (printf, 2, 3)) cprintf(rad_listen_t *listener, char const *fmt, ...)
283 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
286 if (listener->status == RAD_LISTEN_STATUS_EOL) return 0;
288 len = write(listener->fd, buffer, len);
289 if (len <= 0) command_close_socket(listener);
292 * FIXME: Keep writing until done?
297 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
300 module_instance_t *mi;
304 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
309 * Hack a "main" HUP thingy
311 if (strcmp(argv[0], "main.log") == 0) {
316 cs = cf_section_find("modules");
319 mi = find_module_instance(cs, argv[0], 0);
321 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
325 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
326 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
331 if (!module_hup_module(mi->cs, mi, time(NULL))) {
332 cprintf(listener, "ERROR: Failed to reload module\n");
336 snprintf(buffer, sizeof(buffer), "modules.%s.hup",
337 cf_section_name1(mi->cs));
338 exec_trigger(NULL, mi->cs, buffer, true);
340 return 1; /* success */
343 static int command_terminate(UNUSED rad_listen_t *listener,
344 UNUSED int argc, UNUSED char *argv[])
346 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
348 return 1; /* success */
351 extern time_t fr_start_time;
353 static int command_uptime(rad_listen_t *listener,
354 UNUSED int argc, UNUSED char *argv[])
358 CTIME_R(&fr_start_time, buffer, sizeof(buffer));
359 cprintf(listener, "Up since %s", buffer); /* no \r\n */
361 return 1; /* success */
364 static int command_show_config(rad_listen_t *listener, int argc, char *argv[])
371 cprintf(listener, "ERROR: No path was given\n");
375 ci = cf_reference_item(main_config.config, main_config.config, argv[0]);
378 if (!cf_item_is_pair(ci)) return 0;
380 cp = cf_itemtopair(ci);
381 value = cf_pair_value(cp);
382 if (!value) return 0;
384 cprintf(listener, "%s\n", value);
386 return 1; /* success */
389 static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
392 * FIXME: Recurse && indent?
394 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
399 char const *name1 = cf_section_name1(cs);
400 char const *name2 = cf_section_name2(cs);
401 CONF_PARSER const *variables = cf_section_parse_table(cs);
404 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
406 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
414 if (variables) for (i = 0; variables[i].name != NULL; i++) {
419 * No base struct offset, data must be the pointer.
420 * If data doesn't exist, ignore the entry, there
421 * must be something wrong.
424 if (!variables[i].data) {
428 data = variables[i].data;;
430 } else if (variables[i].data) {
431 data = variables[i].data;;
434 data = (((char const *)base) + variables[i].offset);
437 switch (variables[i].type) {
439 cprintf(listener, "%.*s%s = ?\n", indent, tabs,
443 case PW_TYPE_INTEGER:
444 cprintf(listener, "%.*s%s = %u\n", indent, tabs,
445 variables[i].name, *(int const *) data);
448 case PW_TYPE_IPV4_ADDR:
449 inet_ntop(AF_INET, data, buffer, sizeof(buffer));
452 case PW_TYPE_IPV6_ADDR:
453 inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
456 case PW_TYPE_BOOLEAN:
457 cprintf(listener, "%.*s%s = %s\n", indent, tabs,
459 ((*(bool const *) data) == false) ? "no" : "yes");
463 case PW_TYPE_FILE_INPUT:
464 case PW_TYPE_FILE_OUTPUT:
466 * FIXME: Escape things in the string!
468 if (*(char const * const *) data) {
469 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
470 variables[i].name, *(char const * const *) data);
472 cprintf(listener, "%.*s%s = \n", indent, tabs,
482 cprintf(listener, "%.*s}\n", indent, tabs);
485 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
488 module_instance_t *mi;
491 cprintf(listener, "ERROR: No module name was given\n");
495 cs = cf_section_find("modules");
498 mi = find_module_instance(cs, argv[0], 0);
500 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
504 cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
506 return 1; /* success */
509 static char const *method_names[RLM_COMPONENT_COUNT] = {
521 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
525 module_instance_t const *mi;
529 cprintf(listener, "ERROR: No module name was given\n");
533 cs = cf_section_find("modules");
536 mi = find_module_instance(cs, argv[0], 0);
538 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
542 mod = mi->entry->module;
544 for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
545 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
548 return 1; /* success */
552 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
555 module_instance_t const *mi;
559 cprintf(listener, "ERROR: No module name was given\n");
563 cs = cf_section_find("modules");
566 mi = find_module_instance(cs, argv[0], 0);
568 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
572 mod = mi->entry->module;
574 if ((mod->type & RLM_TYPE_THREAD_UNSAFE) != 0)
575 cprintf(listener, "\tthread-unsafe\n");
578 if ((mod->type & RLM_TYPE_CHECK_CONFIG_UNSAFE) != 0)
579 cprintf(listener, "\tno-check-config\n");
582 if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
583 cprintf(listener, "\treload-on-hup\n");
585 return 1; /* success */
588 static int command_show_module_status(rad_listen_t *listener, int argc, char *argv[])
591 const module_instance_t *mi;
594 cprintf(listener, "ERROR: No module name was given\n");
598 cs = cf_section_find("modules");
601 mi = find_module_instance(cs, argv[0], 0);
603 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
608 cprintf(listener, "alive\n");
610 cprintf(listener, "%s\n", fr_int2str(mod_rcode_table, mi->code, "<invalid>"));
614 return 1; /* success */
619 * Show all loaded modules
621 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
623 CONF_SECTION *cs, *subcs;
625 cs = cf_section_find("modules");
629 while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
630 char const *name1 = cf_section_name1(subcs);
631 char const *name2 = cf_section_name2(subcs);
633 module_instance_t *mi;
636 mi = find_module_instance(cs, name2, 0);
639 cprintf(listener, "\t%s (%s)\n", name2, name1);
641 mi = find_module_instance(cs, name1, 0);
644 cprintf(listener, "\t%s\n", name1);
648 return 1; /* success */
652 static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
656 char const *type, *state, *proto;
660 for (i = 0; i < 256; i++) {
661 home = home_server_bynumber(i);
665 * Internal "virtual" home server.
667 if (home->ipaddr.af == AF_UNSPEC) continue;
669 if (home->type == HOME_TYPE_AUTH) {
672 } else if (home->type == HOME_TYPE_ACCT) {
676 } else if (home->type == HOME_TYPE_COA) {
682 if (home->proto == IPPROTO_UDP) {
686 else if (home->proto == IPPROTO_TCP) {
692 if (home->state == HOME_STATE_ALIVE) {
695 } else if (home->state == HOME_STATE_ZOMBIE) {
698 } else if (home->state == HOME_STATE_IS_DEAD) {
701 } else if (home->state == HOME_STATE_UNKNOWN) {
702 time_t now = time(NULL);
705 * We've recently received a packet, so
706 * the home server seems to be alive.
708 * The *reported* state changes because
709 * the internal state machine NEEDS THE
710 * RIGHT STATE. However, reporting that
711 * to the admin will confuse them.
712 * So... we lie. No, that dress doesn't
713 * make you look fat...
715 if ((home->last_packet_recv + (int)home->ping_interval) >= now) {
723 cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\n",
724 ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
725 home->port, proto, type, state,
726 home->currently_outstanding);
733 static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
739 for (i = 0; i < 256; i++) {
740 client = client_findbynumber(NULL, i);
743 ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
745 if (((client->ipaddr.af == AF_INET) &&
746 (client->ipaddr.prefix != 32)) ||
747 ((client->ipaddr.af == AF_INET6) &&
748 (client->ipaddr.prefix != 128))) {
749 cprintf(listener, "\t%s/%d\n", buffer, client->ipaddr.prefix);
751 cprintf(listener, "\t%s\n", buffer);
759 static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
761 cprintf(listener, "%s\n", radiusd_version);
765 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
770 cprintf(listener, "ERROR: Must specify <number>\n");
774 number = atoi(argv[0]);
775 if ((number < 0) || (number > 4)) {
776 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
780 fr_debug_flag = debug_flag = number;
785 static char debug_log_file_buffer[1024];
787 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
789 if (debug_flag && default_log.dst == L_DST_STDOUT) {
790 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
794 if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) != NULL)) {
795 cprintf(listener, "ERROR: Cannot direct debug logs to absolute path.\n");
798 default_log.debug_file = NULL;
800 if (argc == 0) return 0;
803 * This looks weird, but it's here to avoid locking
804 * a mutex for every log message.
806 memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer));
809 * Debug files always go to the logging directory.
811 snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer),
812 "%s/%s", radlog_dir, argv[0]);
814 default_log.debug_file = &debug_log_file_buffer[0];
819 extern fr_cond_t *debug_condition;
820 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
824 fr_cond_t *new_condition = NULL;
825 char *p, buffer[1024];
831 talloc_free(debug_condition);
832 debug_condition = NULL;
837 ((argv[0][0] == '"') || (argv[0][0] == '\'')))) {
840 for (i = 0; i < argc; i++) {
843 len = strlcpy(p, argv[i], buffer + sizeof(buffer) - p);
851 * Backwards compatibility. De-escape the string.
863 ERROR("Failed parsing condition '%s': Unexpected end of string", argv[0]);
869 ERROR("Failed parsing condition '%s': Unexpected text after end of string", argv[0]);
886 if (fr_condition_tokenize(NULL, NULL, buffer, &new_condition, &error, FR_COND_ONE_PASS) < 0) {
887 ERROR("Failed parsing condition '%s': %s", buffer, error);
892 * Delete old condition.
894 * This is thread-safe because the condition is evaluated
895 * in the main server thread, along with this code.
897 talloc_free(debug_condition);
898 debug_condition = new_condition;
903 static int command_show_debug_condition(rad_listen_t *listener,
904 UNUSED int argc, UNUSED char *argv[])
908 if (!debug_condition) return 0;
910 fr_cond_sprint(buffer, sizeof(buffer), debug_condition);
912 cprintf(listener, "%s\n", buffer);
917 static int command_show_debug_file(rad_listen_t *listener,
918 UNUSED int argc, UNUSED char *argv[])
920 if (!default_log.debug_file) return 0;
922 cprintf(listener, "%s\n", default_log.debug_file);
927 static int command_show_debug_level(rad_listen_t *listener,
928 UNUSED int argc, UNUSED char *argv[])
930 cprintf(listener, "%d\n", debug_flag);
935 static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[])
939 int proto = IPPROTO_UDP;
942 cprintf(listener, "ERROR: Must specify <ipaddr>\n");
946 if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
947 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
954 if (strcmp(argv[1], "tcp") == 0) {
957 } else if (strcmp(argv[1], "udp") == 0) {
961 cprintf(listener, "ERROR: Unknown protocol %s. Please use \"udp\" or \"tcp\"\n",
968 client = client_find(NULL, &ipaddr, proto);
970 cprintf(listener, "ERROR: No such client\n");
978 static home_server_t *get_home_server(rad_listen_t *listener, int argc,
979 char *argv[], int *last)
983 int proto = IPPROTO_UDP;
987 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto]\n");
991 if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
992 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
997 port = atoi(argv[1]);
1001 if (strcmp(argv[2], "udp") == 0) {
1002 proto = IPPROTO_UDP;
1003 if (last) *last = 3;
1006 if (strcmp(argv[2], "tcp") == 0) {
1007 proto = IPPROTO_TCP;
1008 if (last) *last = 3;
1013 home = home_server_find(&ipaddr, port, proto);
1015 cprintf(listener, "ERROR: No such home server\n");
1022 static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
1025 home_server_t *home;
1028 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto] <state>\n");
1032 home = get_home_server(listener, argc, argv, &last);
1037 if (strcmp(argv[last], "alive") == 0) {
1038 revive_home_server(home);
1040 } else if (strcmp(argv[last], "dead") == 0) {
1043 gettimeofday(&now, NULL); /* we do this WAY too ofetn */
1044 mark_home_server_dead(home, &now);
1047 cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[last]);
1054 static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
1056 home_server_t *home;
1058 home = get_home_server(listener, argc, argv, NULL);
1063 switch (home->state) {
1064 case HOME_STATE_ALIVE:
1065 cprintf(listener, "alive\n");
1068 case HOME_STATE_IS_DEAD:
1069 cprintf(listener, "dead\n");
1072 case HOME_STATE_ZOMBIE:
1073 cprintf(listener, "zombie\n");
1076 case HOME_STATE_UNKNOWN:
1077 cprintf(listener, "unknown\n");
1081 cprintf(listener, "invalid\n");
1090 * For encode/decode stuff
1092 static int null_socket_dencode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
1097 static int null_socket_send(UNUSED rad_listen_t *listener, REQUEST *request)
1103 output_file = request_data_reference(request, null_socket_send, 0);
1105 ERROR("No output file for injected packet %d", request->number);
1109 fp = fopen(output_file, "w");
1111 ERROR("Failed to send injected file to %s: %s",
1112 output_file, fr_syserror(errno));
1116 if (request->reply->code != 0) {
1117 char const *what = "reply";
1121 if (request->reply->code < FR_MAX_PACKET_CODE) {
1122 what = fr_packet_codes[request->reply->code];
1125 fprintf(fp, "%s\n", what);
1128 RDEBUG("Injected %s packet to host %s port 0 code=%d, id=%d", what,
1129 inet_ntop(request->reply->src_ipaddr.af,
1130 &request->reply->src_ipaddr.ipaddr,
1131 buffer, sizeof(buffer)),
1132 request->reply->code, request->reply->id);
1135 for (vp = fr_cursor_init(&cursor, &request->reply->vps);
1137 vp = fr_cursor_next(&cursor)) {
1138 vp_prints(buffer, sizeof(buffer), vp);
1139 fprintf(fp, "%s\n", buffer);
1141 RDEBUG("\t%s", buffer);
1150 static rad_listen_t *get_socket(rad_listen_t *listener, int argc,
1151 char *argv[], int *last)
1155 int proto = IPPROTO_UDP;
1159 cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto]\n");
1163 if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
1164 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1169 port = atoi(argv[1]);
1171 if (last) *last = 2;
1173 if (strcmp(argv[2], "udp") == 0) {
1174 proto = IPPROTO_UDP;
1175 if (last) *last = 3;
1178 if (strcmp(argv[2], "tcp") == 0) {
1179 proto = IPPROTO_TCP;
1180 if (last) *last = 3;
1185 sock = listener_find_byipaddr(&ipaddr, port, proto);
1187 cprintf(listener, "ERROR: No such listen section\n");
1195 static int command_inject_to(rad_listen_t *listener, int argc, char *argv[])
1197 fr_command_socket_t *sock = listener->data;
1198 listen_socket_t *data;
1199 rad_listen_t *found;
1201 found = get_socket(listener, argc, argv, NULL);
1207 sock->inject_listener = found;
1208 sock->dst_ipaddr = data->my_ipaddr;
1209 sock->dst_port = data->my_port;
1214 static int command_inject_from(rad_listen_t *listener, int argc, char *argv[])
1217 fr_command_socket_t *sock = listener->data;
1220 cprintf(listener, "ERROR: No <ipaddr> was given\n");
1224 if (!sock->inject_listener) {
1225 cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject from\"\n");
1229 sock->src_ipaddr.af = AF_UNSPEC;
1230 if (ip_hton(&sock->src_ipaddr, AF_UNSPEC, argv[0], false) < 0) {
1231 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1236 client = client_listener_find(sock->inject_listener, &sock->src_ipaddr,
1239 cprintf(listener, "ERROR: No such client %s\n", argv[0]);
1242 sock->inject_client = client;
1247 static int command_inject_file(rad_listen_t *listener, int argc, char *argv[])
1249 static int inject_id = 0;
1252 fr_command_socket_t *sock = listener->data;
1254 RADIUS_PACKET *packet;
1258 RAD_REQUEST_FUNP fun = NULL;
1262 cprintf(listener, "ERROR: You must specify <input-file> <output-file>\n");
1266 if (!sock->inject_listener) {
1267 cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject file\"\n");
1271 if (!sock->inject_client) {
1272 cprintf(listener, "ERROR: You must specify \"inject from\" before using \"inject file\"\n");
1277 * Output files always go to the logging directory.
1279 snprintf(buffer, sizeof(buffer), "%s/%s", radlog_dir, argv[1]);
1281 fp = fopen(argv[0], "r");
1283 cprintf(listener, "ERROR: Failed opening %s: %s\n",
1284 argv[0], fr_syserror(errno));
1288 ret = readvp2(&vp, NULL, fp, &filedone);
1291 cprintf(listener, "ERROR: Failed reading attributes from %s: %s\n",
1292 argv[0], fr_strerror());
1296 fake = talloc(NULL, rad_listen_t);
1297 memcpy(fake, sock->inject_listener, sizeof(*fake));
1300 * Re-write the IO for the listener.
1302 fake->encode = null_socket_dencode;
1303 fake->decode = null_socket_dencode;
1304 fake->send = null_socket_send;
1306 packet = rad_alloc(NULL, false);
1307 packet->src_ipaddr = sock->src_ipaddr;
1308 packet->src_port = 0;
1310 packet->dst_ipaddr = sock->dst_ipaddr;
1311 packet->dst_port = sock->dst_port;
1313 packet->id = inject_id++;
1315 if (fake->type == RAD_LISTEN_AUTH) {
1316 packet->code = PW_CODE_ACCESS_REQUEST;
1317 fun = rad_authenticate;
1320 #ifdef WITH_ACCOUNTING
1321 packet->code = PW_CODE_ACCOUNTING_REQUEST;
1322 fun = rad_accounting;
1324 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1332 DEBUG("Injecting %s packet from host %s port 0 code=%d, id=%d",
1333 fr_packet_codes[packet->code],
1334 inet_ntop(packet->src_ipaddr.af,
1335 &packet->src_ipaddr.ipaddr,
1336 buffer, sizeof(buffer)),
1337 packet->code, packet->id);
1339 for (vp = fr_cursor_init(&cursor, &packet->vps);
1341 vp = fr_cursor_next(&cursor)) {
1342 vp_prints(buffer, sizeof(buffer), vp);
1343 DEBUG("\t%s", buffer);
1346 WARN("INJECTION IS LEAKING MEMORY!");
1349 if (!request_receive(fake, packet, sock->inject_client, fun)) {
1350 cprintf(listener, "ERROR: Failed to inject request. See log file for details\n");
1358 * Remember what the output file is, and remember to
1359 * delete the fake listener when done.
1361 request_data_add(request, null_socket_send, 0, talloc_typed_strdup(NULL, buffer), true);
1362 request_data_add(request, null_socket_send, 1, fake, true);
1370 static fr_command_table_t command_table_inject[] = {
1372 "inject to <ipaddr> <port> - Inject packets to the destination IP and port.",
1373 command_inject_to, NULL },
1376 "inject from <ipaddr> - Inject packets as if they came from <ipaddr>",
1377 command_inject_from, NULL },
1380 "inject file <input-file> <output-file> - Inject packet from input-file>, with results sent to <output-file>",
1381 command_inject_file, NULL },
1383 { NULL, 0, NULL, NULL, NULL }
1386 static fr_command_table_t command_table_debug[] = {
1387 { "condition", FR_WRITE,
1388 "debug condition [condition] - Enable debugging for requests matching [condition]",
1389 command_debug_condition, NULL },
1391 { "level", FR_WRITE,
1392 "debug level <number> - Set debug level to <number>. Higher is more debugging.",
1393 command_debug_level, NULL },
1396 "debug file [filename] - Send all debugging output to [filename]",
1397 command_debug_file, NULL },
1399 { NULL, 0, NULL, NULL, NULL }
1402 static fr_command_table_t command_table_show_debug[] = {
1403 { "condition", FR_READ,
1404 "show debug condition - Shows current debugging condition.",
1405 command_show_debug_condition, NULL },
1408 "show debug level - Shows current debugging level.",
1409 command_show_debug_level, NULL },
1412 "show debug file - Shows current debugging file.",
1413 command_show_debug_file, NULL },
1415 { NULL, 0, NULL, NULL, NULL }
1418 static fr_command_table_t command_table_show_module[] = {
1419 { "config", FR_READ,
1420 "show module config <module> - show configuration for given module",
1421 command_show_module_config, NULL },
1423 "show module flags <module> - show other module properties",
1424 command_show_module_flags, NULL },
1426 "show module list - shows list of loaded modules",
1427 command_show_modules, NULL },
1428 { "methods", FR_READ,
1429 "show module methods <module> - show sections where <module> may be used",
1430 command_show_module_methods, NULL },
1431 { "status", FR_READ,
1432 "show module status <module> - show the module status",
1433 command_show_module_status, NULL },
1435 { NULL, 0, NULL, NULL, NULL }
1438 static fr_command_table_t command_table_show_client[] = {
1440 "show client list - shows list of global clients",
1441 command_show_clients, NULL },
1443 { NULL, 0, NULL, NULL, NULL }
1447 static fr_command_table_t command_table_show_home[] = {
1449 "show home_server list - shows list of home servers",
1450 command_show_home_servers, NULL },
1452 "show home_server state <ipaddr> <port> [proto] - shows state of given home server",
1453 command_show_home_server_state, NULL },
1455 { NULL, 0, NULL, NULL, NULL }
1460 static fr_command_table_t command_table_show[] = {
1461 { "client", FR_READ,
1462 "show client <command> - do sub-command of client",
1463 NULL, command_table_show_client },
1464 { "config", FR_READ,
1465 "show config <path> - shows the value of configuration option <path>",
1466 command_show_config, NULL },
1468 "show debug <command> - show debug properties",
1469 NULL, command_table_show_debug },
1471 { "home_server", FR_READ,
1472 "show home_server <command> - do sub-command of home_server",
1473 NULL, command_table_show_home },
1475 { "module", FR_READ,
1476 "show module <command> - do sub-command of module",
1477 NULL, command_table_show_module },
1478 { "uptime", FR_READ,
1479 "show uptime - shows time at which server started",
1480 command_uptime, NULL },
1481 { "version", FR_READ,
1482 "show version - Prints version of the running server",
1483 command_show_version, NULL },
1484 { NULL, 0, NULL, NULL, NULL }
1488 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
1493 module_instance_t *mi;
1494 CONF_PARSER const *variables;
1498 cprintf(listener, "ERROR: No module name or variable was given\n");
1502 cs = cf_section_find("modules");
1505 mi = find_module_instance(cs, argv[0], 0);
1507 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1511 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
1512 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
1516 variables = cf_section_parse_table(mi->cs);
1518 cprintf(listener, "ERROR: Cannot find configuration for module\n");
1523 for (i = 0; variables[i].name != NULL; i++) {
1525 * FIXME: Recurse into sub-types somehow...
1527 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
1529 if (strcmp(variables[i].name, argv[1]) == 0) {
1536 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
1540 i = rcode; /* just to be safe */
1543 * It's not part of the dynamic configuration. The module
1544 * needs to re-parse && validate things.
1546 if (variables[i].data) {
1547 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
1551 data = ((char *) mi->insthandle) + variables[i].offset;
1553 cp = cf_pair_find(mi->cs, argv[1]);
1557 * Replace the OLD value in the configuration file with
1560 * FIXME: Parse argv[2] depending on it's data type!
1561 * If it's a string, look for leading single/double quotes,
1562 * end then call tokenize functions???
1564 cf_pair_replace(mi->cs, cp, argv[2]);
1566 rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, data, argv[2]);
1568 cprintf(listener, "ERROR: Failed to parse value\n");
1572 return 1; /* success */
1575 static int command_set_module_status(rad_listen_t *listener, int argc, char *argv[])
1578 module_instance_t *mi;
1581 cprintf(listener, "ERROR: No module name or status was given\n");
1585 cs = cf_section_find("modules");
1588 mi = find_module_instance(cs, argv[0], 0);
1590 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1595 if (strcmp(argv[1], "alive") == 0) {
1598 } else if (strcmp(argv[1], "dead") == 0) {
1599 mi->code = RLM_MODULE_FAIL;
1605 rcode = fr_str2int(mod_rcode_table, argv[1], -1);
1607 cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[1]);
1615 return 1; /* success */
1619 static char const *elapsed_names[8] = {
1620 "1us", "10us", "100us", "1ms", "10ms", "100ms", "1s", "10s"
1624 #ifdef WITH_STATS_64BIT
1626 #define PU "%" PRIu64
1632 #define PU "%" PRIu32
1638 static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
1639 int auth, int server)
1643 cprintf(listener, "\trequests\t" PU "\n", stats->total_requests);
1644 cprintf(listener, "\tresponses\t" PU "\n", stats->total_responses);
1647 cprintf(listener, "\taccepts\t\t" PU "\n",
1648 stats->total_access_accepts);
1649 cprintf(listener, "\trejects\t\t" PU "\n",
1650 stats->total_access_rejects);
1651 cprintf(listener, "\tchallenges\t" PU "\n",
1652 stats->total_access_challenges);
1655 cprintf(listener, "\tdup\t\t" PU "\n", stats->total_dup_requests);
1656 cprintf(listener, "\tinvalid\t\t" PU "\n", stats->total_invalid_requests);
1657 cprintf(listener, "\tmalformed\t" PU "\n", stats->total_malformed_requests);
1658 cprintf(listener, "\tbad_authenticator\t" PU "\n", stats->total_bad_authenticators);
1659 cprintf(listener, "\tdropped\t\t" PU "\n", stats->total_packets_dropped);
1660 cprintf(listener, "\tunknown_types\t" PU "\n", stats->total_unknown_types);
1663 cprintf(listener, "\ttimeouts\t" PU "\n", stats->total_timeouts);
1666 cprintf(listener, "\tlast_packet\t%" PRId64 "\n", (int64_t) stats->last_packet);
1667 for (i = 0; i < 8; i++) {
1668 cprintf(listener, "\telapsed.%s\t%u\n",
1669 elapsed_names[i], stats->elapsed[i]);
1676 static FR_NAME_NUMBER state_names[] = {
1677 { "unopened", STATE_UNOPENED },
1678 { "unlocked", STATE_UNLOCKED },
1679 { "header", STATE_HEADER },
1680 { "reading", STATE_READING },
1681 { "queued", STATE_QUEUED },
1682 { "running", STATE_RUNNING },
1683 { "no-reply", STATE_NO_REPLY },
1684 { "replied", STATE_REPLIED },
1689 static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
1692 listen_detail_t *data;
1696 cprintf(listener, "ERROR: Must specify <filename>\n");
1701 for (this = main_config.listen; this != NULL; this = this->next) {
1702 if (this->type != RAD_LISTEN_DETAIL) continue;
1705 if (strcmp(argv[1], data->filename) != 0) continue;
1711 cprintf(listener, "ERROR: No detail file listener\n");
1715 cprintf(listener, "\tstate\t%s\n",
1716 fr_int2str(state_names, data->state, "?"));
1718 if ((data->state == STATE_UNOPENED) ||
1719 (data->state == STATE_UNLOCKED)) {
1724 * Race conditions: file might not exist.
1726 if (stat(data->filename_work, &buf) < 0) {
1727 cprintf(listener, "packets\t0\n");
1728 cprintf(listener, "tries\t0\n");
1729 cprintf(listener, "offset\t0\n");
1730 cprintf(listener, "size\t0\n");
1734 cprintf(listener, "packets\t%d\n", data->packets);
1735 cprintf(listener, "tries\t%d\n", data->tries);
1736 cprintf(listener, "offset\t%u\n", (unsigned int) data->offset);
1737 cprintf(listener, "size\t%u\n", (unsigned int) buf.st_size);
1744 static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
1746 home_server_t *home;
1749 cprintf(listener, "ERROR: Must specify [auth/acct] OR <ipaddr> <port>\n");
1754 #ifdef WITH_ACCOUNTING
1755 if (strcmp(argv[0], "acct") == 0) {
1756 return command_print_stats(listener,
1757 &proxy_acct_stats, 0, 1);
1760 if (strcmp(argv[0], "auth") == 0) {
1761 return command_print_stats(listener,
1762 &proxy_auth_stats, 1, 1);
1765 cprintf(listener, "ERROR: Should specify [auth/acct]\n");
1769 home = get_home_server(listener, argc, argv, NULL);
1774 command_print_stats(listener, &home->stats,
1775 (home->type == HOME_TYPE_AUTH), 1);
1776 cprintf(listener, "\toutstanding\t%d\n", home->currently_outstanding);
1781 static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
1785 RADCLIENT *client, fake;
1788 cprintf(listener, "ERROR: Must specify [auth/acct]\n");
1794 * Global statistics.
1796 fake.auth = radius_auth_stats;
1797 #ifdef WITH_ACCOUNTING
1798 fake.auth = radius_acct_stats;
1801 fake.coa = radius_coa_stats;
1802 fake.dsc = radius_dsc_stats;
1808 * Per-client statistics.
1810 client = get_client(listener, argc - 1, argv + 1);
1816 if (strcmp(argv[0], "auth") == 0) {
1818 stats = &client->auth;
1820 } else if (strcmp(argv[0], "acct") == 0) {
1821 #ifdef WITH_ACCOUNTING
1823 stats = &client->acct;
1825 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1829 } else if (strcmp(argv[0], "coa") == 0) {
1832 stats = &client->coa;
1834 cprintf(listener, "ERROR: This server was built without CoA support.\n");
1838 } else if (strcmp(argv[0], "disconnect") == 0) {
1841 stats = &client->dsc;
1843 cprintf(listener, "ERROR: This server was built without CoA support.\n");
1848 cprintf(listener, "ERROR: Unknown statistics type\n");
1853 * Global results for all client.
1856 #ifdef WITH_ACCOUNTING
1858 return command_print_stats(listener,
1859 &radius_acct_stats, auth, 0);
1862 return command_print_stats(listener, &radius_auth_stats, auth, 0);
1865 return command_print_stats(listener, stats, auth, 0);
1869 static int command_stats_socket(rad_listen_t *listener, int argc, char *argv[])
1874 sock = get_socket(listener, argc, argv, NULL);
1879 if (sock->type != RAD_LISTEN_AUTH) auth = false;
1881 return command_print_stats(listener, &sock->stats, auth, 0);
1883 #endif /* WITH_STATS */
1886 #ifdef WITH_DYNAMIC_CLIENTS
1887 static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
1892 cprintf(listener, "ERROR: <file> is required\n");
1897 * Read the file and generate the client.
1899 c = client_read(argv[0], false, false);
1901 cprintf(listener, "ERROR: Unknown error reading client file.\n");
1905 if (!client_add(NULL, c)) {
1906 cprintf(listener, "ERROR: Unknown error inserting new client.\n");
1915 static int command_del_client(rad_listen_t *listener, int argc, char *argv[])
1919 client = get_client(listener, argc, argv);
1920 if (!client) return 0;
1922 if (!client->dynamic) {
1923 cprintf(listener, "ERROR: Client %s was not dynamically defined.\n", argv[0]);
1928 * DON'T delete it. Instead, mark it as "dead now". The
1929 * next time we receive a packet for the client, it will
1932 * If we don't receive a packet from it, the client
1933 * structure will stick around for a while. Oh well...
1935 client->lifetime = 1;
1941 static fr_command_table_t command_table_del_client[] = {
1942 { "ipaddr", FR_WRITE,
1943 "del client ipaddr <ipaddr> - Delete a dynamically created client",
1944 command_del_client, NULL },
1946 { NULL, 0, NULL, NULL, NULL }
1950 static fr_command_table_t command_table_del[] = {
1951 { "client", FR_WRITE,
1952 "del client <command> - Delete client configuration commands",
1953 NULL, command_table_del_client },
1955 { NULL, 0, NULL, NULL, NULL }
1959 static fr_command_table_t command_table_add_client[] = {
1961 "add client file <filename> - Add new client definition from <filename>",
1962 command_add_client_file, NULL },
1964 { NULL, 0, NULL, NULL, NULL }
1968 static fr_command_table_t command_table_add[] = {
1969 { "client", FR_WRITE,
1970 "add client <command> - Add client configuration commands",
1971 NULL, command_table_add_client },
1973 { NULL, 0, NULL, NULL, NULL }
1978 static fr_command_table_t command_table_set_home[] = {
1979 { "state", FR_WRITE,
1980 "set home_server state <ipaddr> <port> [proto] [alive|dead] - set state for given home server",
1981 command_set_home_server_state, NULL },
1983 { NULL, 0, NULL, NULL, NULL }
1987 static fr_command_table_t command_table_set_module[] = {
1988 { "config", FR_WRITE,
1989 "set module config <module> variable value - set configuration for <module>",
1990 command_set_module_config, NULL },
1992 { "status", FR_WRITE,
1993 "set module status <module> [alive|...] - set the module status to be alive (operating normally), or force a particular code (ok,fail, etc.)",
1994 command_set_module_status, NULL },
1996 { NULL, 0, NULL, NULL, NULL }
2000 static fr_command_table_t command_table_set[] = {
2001 { "module", FR_WRITE,
2002 "set module <command> - set module commands",
2003 NULL, command_table_set_module },
2005 { "home_server", FR_WRITE,
2006 "set home_server <command> - set home server commands",
2007 NULL, command_table_set_home },
2010 { NULL, 0, NULL, NULL, NULL }
2015 static fr_command_table_t command_table_stats[] = {
2016 { "client", FR_READ,
2017 "stats client [auth/acct] <ipaddr> "
2021 "- show statistics for given client, or for all clients (auth or acct)",
2022 command_stats_client, NULL },
2025 { "detail", FR_READ,
2026 "stats detail <filename> - show statistics for the given detail file",
2027 command_stats_detail, NULL },
2031 { "home_server", FR_READ,
2032 "stats home_server [<ipaddr>/auth/acct] <port> - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
2033 command_stats_home_server, NULL },
2036 { "socket", FR_READ,
2037 "stats socket <ipaddr> <port> "
2041 "- show statistics for given socket",
2042 command_stats_socket, NULL },
2044 { NULL, 0, NULL, NULL, NULL }
2048 static fr_command_table_t command_table[] = {
2049 #ifdef WITH_DYNAMIC_CLIENTS
2050 { "add", FR_WRITE, NULL, NULL, command_table_add },
2052 { "debug", FR_WRITE,
2053 "debug <command> - debugging commands",
2054 NULL, command_table_debug },
2055 #ifdef WITH_DYNAMIC_CLIENTS
2056 { "del", FR_WRITE, NULL, NULL, command_table_del },
2059 "hup [module] - sends a HUP signal to the server, or optionally to one module",
2060 command_hup, NULL },
2061 { "inject", FR_WRITE,
2062 "inject <command> - commands to inject packets into a running server",
2063 NULL, command_table_inject },
2064 { "reconnect", FR_READ,
2065 "reconnect - reconnect to a running server",
2066 NULL, NULL }, /* just here for "help" */
2067 { "terminate", FR_WRITE,
2068 "terminate - terminates the server, and cause it to exit",
2069 command_terminate, NULL },
2070 { "set", FR_WRITE, NULL, NULL, command_table_set },
2071 { "show", FR_READ, NULL, NULL, command_table_show },
2073 { "stats", FR_READ, NULL, NULL, command_table_stats },
2076 { NULL, 0, NULL, NULL, NULL }
2080 static void command_socket_free(rad_listen_t *this)
2082 fr_command_socket_t *cmd = this->data;
2085 * If it's a TCP socket, don't do anything.
2087 if (cmd->magic != COMMAND_SOCKET_MAGIC) {
2091 if (!cmd->copy) return;
2097 * Parse the unix domain sockets.
2099 * FIXME: TCP + SSL, after RadSec is in.
2101 static int command_socket_parse_unix(CONF_SECTION *cs, rad_listen_t *this)
2103 fr_command_socket_t *sock;
2105 if (check_config) return 0;
2109 if (cf_section_parse(cs, sock, command_config) < 0) {
2113 sock->magic = COMMAND_SOCKET_MAGIC;
2115 if (sock->path) sock->copy = talloc_typed_strdup(sock, sock->path);
2117 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2118 if (sock->uid_name) {
2121 pw = getpwnam(sock->uid_name);
2123 ERROR("Failed getting uid for %s: %s",
2124 sock->uid_name, fr_syserror(errno));
2128 sock->uid = pw->pw_uid;
2133 if (sock->gid_name) {
2136 gr = getgrnam(sock->gid_name);
2138 ERROR("Failed getting gid for %s: %s",
2139 sock->gid_name, fr_syserror(errno));
2142 sock->gid = gr->gr_gid;
2147 #else /* can't get uid or gid of connecting user */
2149 if (sock->uid_name || sock->gid_name) {
2150 ERROR("System does not support uid or gid authentication for sockets");
2156 if (!sock->mode_name) {
2157 sock->co.mode = FR_READ;
2159 sock->co.mode = fr_str2int(mode_names, sock->mode_name, 0);
2160 if (!sock->co.mode) {
2161 ERROR("Invalid mode name \"%s\"",
2168 * FIXME: check for absolute pathnames?
2169 * check for uid/gid on the other end...
2172 this->fd = fr_server_domain_socket(sock->path);
2177 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2179 * Don't chown it from (possibly) non-root to root.
2180 * Do chown it from (possibly) root to non-root.
2182 if ((sock->uid != (uid_t) -1) || (sock->gid != (gid_t) -1)) {
2184 if (fchown(this->fd, sock->uid, sock->gid) < 0) {
2185 ERROR("Failed setting ownership of %s: %s",
2186 sock->path, fr_syserror(errno));
2197 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
2200 CONF_PAIR const *cp;
2201 listen_socket_t *sock;
2203 cp = cf_pair_find(cs, "socket");
2204 if (cp) return command_socket_parse_unix(cs, this);
2206 rcode = common_socket_parse(cs, this);
2207 if (rcode < 0) return -1;
2212 "TLS is not supported for control sockets");
2218 if (sock->proto != IPPROTO_TCP) {
2220 "UDP is not supported for control sockets");
2227 static int command_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
2229 fr_command_socket_t *sock = this->data;
2231 if (sock->magic != COMMAND_SOCKET_MAGIC) {
2232 return common_socket_print(this, buffer, bufsize);
2235 snprintf(buffer, bufsize, "command file %s", sock->path);
2241 * String split routine. Splits an input string IN PLACE
2242 * into pieces, based on spaces.
2244 static int str2argvX(char *str, char **argv, int max_argc)
2249 if (argc >= max_argc) return argc;
2252 * Chop out comments early.
2259 while ((*str == ' ') ||
2262 (*str == '\n')) *(str++) = '\0';
2264 if (!*str) return argc;
2268 if ((*str == '\'') || (*str == '"')) {
2281 * Handle \" and nothing else.
2296 (*str != '\n')) str++;
2302 static void print_help(rad_listen_t *listener,
2303 fr_command_table_t *table, int recursive)
2307 for (i = 0; table[i].command != NULL; i++) {
2308 if (table[i].help) {
2309 cprintf(listener, "%s\n",
2312 cprintf(listener, "%s <command> - do sub-command of %s\n",
2313 table[i].command, table[i].command);
2316 if (recursive && table[i].table) {
2317 print_help(listener, table[i].table, recursive);
2322 #define MAX_ARGV (16)
2325 * Check if an incoming request is "ok"
2327 * It takes packets, not requests. It sees if the packet looks
2328 * OK. If so, it does a number of sanity checks on it.
2330 static int command_domain_recv_co(rad_listen_t *listener, fr_cs_buffer_t *co)
2335 char *my_argv[MAX_ARGV], **argv;
2336 fr_command_table_t *table;
2342 len = recv(listener->fd, co->buffer + co->offset,
2343 sizeof(co->buffer) - co->offset - 1, 0);
2344 if (len == 0) goto close_socket; /* clean close */
2347 if ((errno == EAGAIN) || (errno == EINTR)) {
2356 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
2358 command_close_socket(listener);
2363 * See if there are multiple lines in the buffer.
2365 p = co->buffer + co->offset;
2368 for (c = 0; c < len; c++) {
2369 if ((*p == '\r') || (*p == '\n')) {
2374 * FIXME: do real buffering...
2375 * handling of CTRL-C, etc.
2380 * \r \n followed by ASCII...
2391 * Saw CR/LF. Set next element, and exit.
2394 co->next = p - co->buffer;
2398 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
2399 ERROR("Line too long!");
2406 DEBUG("radmin> %s", co->buffer);
2408 argc = str2argvX(co->buffer, my_argv, MAX_ARGV);
2409 if (argc == 0) goto do_next; /* empty strings are OK */
2412 cprintf(listener, "ERROR: Failed parsing command.\n");
2418 for (len = 0; len <= co->offset; len++) {
2419 if (co->buffer[len] < 0x20) {
2420 co->buffer[len] = '\0';
2426 * Hard-code exit && quit.
2428 if ((strcmp(argv[0], "exit") == 0) ||
2429 (strcmp(argv[0], "quit") == 0)) goto close_socket;
2431 table = command_table;
2434 for (i = 0; table[i].command != NULL; i++) {
2435 if (strcmp(table[i].command, argv[0]) == 0) {
2437 * Check permissions.
2439 if (((co->mode & FR_WRITE) == 0) &&
2440 ((table[i].mode & FR_WRITE) != 0)) {
2441 cprintf(listener, "ERROR: You do not have write permission. See \"mode = rw\" in the \"listen\" section for this socket.\n");
2445 if (table[i].table) {
2447 * This is the last argument, but
2448 * there's a sub-table. Print help.
2452 table = table[i].table;
2458 table = table[i].table;
2462 if ((argc == 2) && (strcmp(argv[1], "?") == 0)) goto do_help;
2464 if (!table[i].func) {
2465 cprintf(listener, "ERROR: Invalid command\n");
2470 table[i].func(listener, argc - 1, argv + 1);
2479 if ((strcmp(argv[0], "help") == 0) ||
2480 (strcmp(argv[0], "?") == 0)) {
2484 if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
2490 print_help(listener, table, recursive);
2494 cprintf(listener, "ERROR: Unknown command \"%s\"\n",
2499 cprintf(listener, "radmin> ");
2501 if (co->next <= co->offset) {
2504 memmove(co->buffer, co->buffer + co->next,
2505 co->offset - co->next);
2506 co->offset -= co->next;
2514 * Write 32-bit magic number && version information.
2516 static int command_write_magic(int newfd, listen_socket_t *sock)
2520 magic = htonl(0xf7eead15);
2521 if (write(newfd, &magic, 4) < 0) {
2522 ERROR("Failed writing initial data to socket: %s",
2523 fr_syserror(errno));
2528 magic = htonl(2); /* protocol version */
2532 if (write(newfd, &magic, 4) < 0) {
2533 ERROR("Failed writing initial data to socket: %s", fr_syserror(errno));
2538 * Write an initial challenge
2544 co = talloc_zero(sock, fr_cs_buffer_t);
2545 sock->packet = (void *) co;
2547 for (i = 0; i < 16; i++) {
2548 co->buffer[i] = fr_rand();
2552 * FIXME: EINTR, etc.
2554 if (write(newfd, co->buffer, 16) < 0) {
2555 ERROR("Failed writing version data to socket: %s", fr_syserror(errno));
2564 static int command_tcp_recv(rad_listen_t *this)
2566 listen_socket_t *sock = this->data;
2567 fr_cs_buffer_t *co = (void *) sock->packet;
2569 rad_assert(co != NULL);
2572 uint8_t expected[16];
2575 * No response yet: keep reading it.
2577 if (co->offset < 16) {
2581 co->buffer + 16 + co->offset, 16 - co->offset);
2584 command_close_socket(this);
2590 if (errno == ECONNRESET) goto close_socket;
2592 if (errno == EINTR) return 0;
2594 ERROR("Failed reading from control socket; %s",
2595 fr_syserror(errno));
2601 if (co->offset < 16) return 0;
2604 fr_hmac_md5(expected, (void const *) sock->client->secret,
2605 strlen(sock->client->secret),
2606 (uint8_t *) co->buffer, 16);
2608 if (rad_digest_cmp(expected,
2609 (uint8_t *) co->buffer + 16, 16 != 0)) {
2610 ERROR("radmin failed challenge: Closing socket");
2618 return command_domain_recv_co(this, co);
2622 * Should never be called. The functions should just call write().
2624 static int command_tcp_send(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
2629 static int command_domain_recv(rad_listen_t *listener)
2631 fr_command_socket_t *sock = listener->data;
2633 return command_domain_recv_co(listener, &sock->co);
2636 static int command_domain_accept(rad_listen_t *listener)
2641 struct sockaddr_storage src;
2642 fr_command_socket_t *sock = listener->data;
2644 salen = sizeof(src);
2646 DEBUG2(" ... new connection request on command socket");
2648 newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
2651 * Non-blocking sockets must handle this.
2653 if (errno == EWOULDBLOCK) {
2657 DEBUG2(" ... failed to accept connection");
2661 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
2663 * Perform user authentication.
2665 if (sock->uid_name || sock->gid_name) {
2669 if (getpeereid(newfd, &uid, &gid) < 0) {
2670 ERROR("Failed getting peer credentials for %s: %s",
2671 sock->path, fr_syserror(errno));
2677 * Only do UID checking if the caller is
2678 * non-root. The superuser can do anything, so
2679 * we might as well let them.
2683 * Allow entry if UID or GID matches.
2685 if (sock->uid_name && (sock->uid == uid)) break;
2686 if (sock->gid_name && (sock->gid == gid)) break;
2688 if (sock->uid_name && (sock->uid != uid)) {
2689 ERROR("Unauthorized connection to %s from uid %ld",
2691 sock->path, (long int) uid);
2696 if (sock->gid_name && (sock->gid != gid)) {
2697 ERROR("Unauthorized connection to %s from gid %ld",
2698 sock->path, (long int) gid);
2706 if (command_write_magic(newfd, NULL) < 0) {
2712 * Add the new listener.
2714 this = listen_alloc(listener, listener->type);
2715 if (!this) return 0;
2718 * Copy everything, including the pointer to the socket
2722 memcpy(this, listener, sizeof(*this));
2723 this->status = RAD_LISTEN_STATUS_INIT;
2725 this->data = sock; /* fix it back */
2727 sock->user[0] = '\0';
2728 sock->path = ((fr_command_socket_t *) listener->data)->path;
2729 sock->co.offset = 0;
2730 sock->co.mode = ((fr_command_socket_t *) listener->data)->co.mode;
2733 this->recv = command_domain_recv;
2736 * Tell the event loop that we have a new FD
2738 radius_update_listener(this);
2745 * Send an authentication response packet
2747 static int command_domain_send(UNUSED rad_listen_t *listener,
2748 UNUSED REQUEST *request)
2754 static int command_socket_encode(UNUSED rad_listen_t *listener,
2755 UNUSED REQUEST *request)
2761 static int command_socket_decode(UNUSED rad_listen_t *listener,
2762 UNUSED REQUEST *request)
2767 #endif /* WITH_COMMAND_SOCKET */