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/modpriv.h>
27 #include <freeradius-devel/conffile.h>
28 #include <freeradius-devel/stats.h>
29 #include <freeradius-devel/realms.h>
34 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
38 #ifdef HAVE_SYS_STAT_H
50 typedef struct fr_command_table_t fr_command_table_t;
52 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
57 struct fr_command_table_t {
59 int mode; /* read/write */
61 fr_command_func_t func;
62 fr_command_table_t *table;
65 #define COMMAND_BUFFER_SIZE (1024)
67 typedef struct fr_command_socket_t {
78 char buffer[COMMAND_BUFFER_SIZE];
79 } fr_command_socket_t;
81 static const CONF_PARSER command_config[] = {
82 { "socket", PW_TYPE_STRING_PTR,
83 offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
84 { "uid", PW_TYPE_STRING_PTR,
85 offsetof(fr_command_socket_t, uid_name), NULL, NULL},
86 { "gid", PW_TYPE_STRING_PTR,
87 offsetof(fr_command_socket_t, gid_name), NULL, NULL},
88 { "mode", PW_TYPE_STRING_PTR,
89 offsetof(fr_command_socket_t, mode_name), NULL, NULL},
91 { NULL, -1, 0, NULL, NULL } /* end the list */
94 static FR_NAME_NUMBER mode_names[] = {
96 { "read-only", FR_READ },
97 { "read-write", FR_READ | FR_WRITE },
98 { "rw", FR_READ | FR_WRITE },
103 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
105 __attribute__ ((format (printf, 2, 3)))
109 #ifndef HAVE_GETPEEREID
110 static int getpeereid(int s, uid_t *euid, gid_t *egid)
116 socklen_t cl = sizeof(cr);
118 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
125 #endif /* SO_PEERCRED */
127 #endif /* HAVE_GETPEEREID */
130 static int fr_server_domain_socket(const char *path)
135 struct sockaddr_un salocal;
139 if (len >= sizeof(salocal.sun_path)) {
140 radlog(L_ERR, "Path too long in socket filename.");
144 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
145 radlog(L_ERR, "Failed creating socket: %s",
150 memset(&salocal, 0, sizeof(salocal));
151 salocal.sun_family = AF_UNIX;
152 memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
154 socklen = SUN_LEN(&salocal);
159 if (stat(path, &buf) < 0) {
160 if (errno != ENOENT) {
161 radlog(L_ERR, "Failed to stat %s: %s",
162 path, strerror(errno));
167 * FIXME: Check the enclosing directory?
169 } else { /* it exists */
170 if (!S_ISREG(buf.st_mode)
172 && !S_ISSOCK(buf.st_mode)
175 radlog(L_ERR, "Cannot turn %s into socket", path);
180 * Refuse to open sockets not owned by us.
182 if (buf.st_uid != geteuid()) {
183 radlog(L_ERR, "We do not own %s", path);
187 if (unlink(path) < 0) {
188 radlog(L_ERR, "Failed to delete %s: %s",
189 path, strerror(errno));
194 if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
195 radlog(L_ERR, "Failed binding to %s: %s",
196 path, strerror(errno));
202 * FIXME: There's a race condition here. But Linux
203 * doesn't seem to permit fchmod on domain sockets.
205 if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
206 radlog(L_ERR, "Failed setting permissions on %s: %s",
207 path, strerror(errno));
212 if (listen(sockfd, 8) < 0) {
213 radlog(L_ERR, "Failed listening to %s: %s",
214 path, strerror(errno));
223 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
224 radlog(L_ERR, "Failure getting socket flags: %s",
231 if( fcntl(sockfd, F_SETFL, flags) < 0) {
232 radlog(L_ERR, "Failure setting socket flags: %s",
243 static void command_close_socket(rad_listen_t *this)
245 this->status = RAD_LISTEN_STATUS_CLOSED;
248 * This removes the socket from the event fd, so no one
249 * will be calling us any more.
257 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
264 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
267 if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0;
269 len = write(listener->fd, buffer, len);
270 if (len <= 0) command_close_socket(listener);
273 * FIXME: Keep writing until done?
278 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
281 module_instance_t *mi;
284 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
288 cs = cf_section_find("modules");
291 mi = find_module_instance(cs, argv[0], 0);
293 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
297 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
298 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
303 if (!module_hup_module(mi->cs, mi, time(NULL))) {
304 cprintf(listener, "ERROR: Failed to reload module\n");
308 return 1; /* success */
311 static int command_terminate(UNUSED rad_listen_t *listener,
312 UNUSED int argc, UNUSED char *argv[])
314 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
316 return 1; /* success */
319 extern time_t fr_start_time;
321 static int command_uptime(rad_listen_t *listener,
322 UNUSED int argc, UNUSED char *argv[])
326 CTIME_R(&fr_start_time, buffer, sizeof(buffer));
327 cprintf(listener, "Up since %s", buffer); /* no \r\n */
329 return 1; /* success */
332 static const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
335 * FIXME: Recurse && indent?
337 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
343 const char *name1 = cf_section_name1(cs);
344 const char *name2 = cf_section_name2(cs);
345 const CONF_PARSER *variables = cf_section_parse_table(cs);
349 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
351 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
359 if (variables) for (i = 0; variables[i].name != NULL; i++) {
361 * No base struct offset, data must be the pointer.
362 * If data doesn't exist, ignore the entry, there
363 * must be something wrong.
366 if (!variables[i].data) {
370 data = variables[i].data;;
372 } else if (variables[i].data) {
373 data = variables[i].data;;
376 data = (((char *)base) + variables[i].offset);
379 switch (variables[i].type) {
381 cprintf(listener, "%.*s%s = ?\n", indent, tabs,
385 case PW_TYPE_INTEGER:
386 cprintf(listener, "%.*s%s = %u\n", indent, tabs,
387 variables[i].name, *(int *) data);
391 inet_ntop(AF_INET, data, buffer, sizeof(buffer));
394 case PW_TYPE_IPV6ADDR:
395 inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
398 case PW_TYPE_BOOLEAN:
399 cprintf(listener, "%.*s%s = %s\n", indent, tabs,
401 ((*(int *) data) == 0) ? "no" : "yes");
404 case PW_TYPE_STRING_PTR:
405 case PW_TYPE_FILENAME:
407 * FIXME: Escape things in the string!
409 if (*(char **) data) {
410 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
411 variables[i].name, *(char **) data);
413 cprintf(listener, "%.*s%s = \n", indent, tabs,
423 cprintf(listener, "%.*s}\n", indent, tabs);
426 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
429 module_instance_t *mi;
432 cprintf(listener, "ERROR: No module name was given\n");
436 cs = cf_section_find("modules");
439 mi = find_module_instance(cs, argv[0], 0);
441 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
445 cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
447 return 1; /* success */
450 static const char *method_names[RLM_COMPONENT_COUNT] = {
462 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
466 const module_instance_t *mi;
470 cprintf(listener, "ERROR: No module name was given\n");
474 cs = cf_section_find("modules");
477 mi = find_module_instance(cs, argv[0], 0);
479 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
483 mod = mi->entry->module;
485 for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
486 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
489 return 1; /* success */
493 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
496 const module_instance_t *mi;
500 cprintf(listener, "ERROR: No module name was given\n");
504 cs = cf_section_find("modules");
507 mi = find_module_instance(cs, argv[0], 0);
509 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
513 mod = mi->entry->module;
515 if ((mod->type & RLM_TYPE_THREAD_SAFE) != 0)
516 cprintf(listener, "\tthread-safe\n");
519 if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
520 cprintf(listener, "\twill-check-config\n");
523 if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
524 cprintf(listener, "\treload-on-hup\n");
526 return 1; /* success */
531 * Show all loaded modules
533 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
535 CONF_SECTION *cs, *subcs;
537 cs = cf_section_find("modules");
541 while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
542 const char *name1 = cf_section_name1(subcs);
543 const char *name2 = cf_section_name2(subcs);
545 module_instance_t *mi;
548 mi = find_module_instance(cs, name2, 0);
551 cprintf(listener, "\t%s (%s)\n", name2, name1);
553 mi = find_module_instance(cs, name1, 0);
556 cprintf(listener, "\t%s\n", name1);
560 return 1; /* success */
564 static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
568 const char *type, *state;
572 for (i = 0; i < 256; i++) {
573 home = home_server_bynumber(i);
577 * Internal "virtual" home server.
579 if (home->ipaddr.af == AF_UNSPEC) continue;
581 if (home->type == HOME_TYPE_AUTH) {
584 } else if (home->type == HOME_TYPE_ACCT) {
589 if (home->state == HOME_STATE_ALIVE) {
592 } else if (home->state == HOME_STATE_ZOMBIE) {
595 } else if (home->state == HOME_STATE_IS_DEAD) {
600 cprintf(listener, "%s\t%d\t%s\t%s\t%d\n",
601 ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
602 home->port, type, state,
603 home->currently_outstanding);
610 static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
616 for (i = 0; i < 256; i++) {
617 client = client_findbynumber(NULL, i);
620 ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
622 if (((client->ipaddr.af == AF_INET) &&
623 (client->prefix != 32)) ||
624 ((client->ipaddr.af == AF_INET6) &&
625 (client->prefix != 128))) {
626 cprintf(listener, "\t%s/%d\n", buffer, client->prefix);
628 cprintf(listener, "\t%s\n", buffer);
636 static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
639 FILE *fp = fdopen(dup(listener->fd), "a");
642 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
647 cprintf(listener, "ERROR: <reference> is required\n");
651 ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
653 cprintf(listener, "ERROR: No such item <reference>\n");
657 if (cf_item_is_section(ci)) {
658 cf_section2xml(fp, cf_itemtosection(ci));
660 } else if (cf_item_is_pair(ci)) {
661 cf_pair2xml(fp, cf_itemtopair(ci));
664 cprintf(listener, "ERROR: No such item <reference>\n");
671 return 1; /* success */
674 static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
676 cprintf(listener, "%s\n", radiusd_version);
680 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
685 cprintf(listener, "ERROR: Must specify <number>\n");
689 number = atoi(argv[0]);
690 if ((number < 0) || (number > 4)) {
691 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
695 fr_debug_flag = debug_flag = number;
700 char *debug_log_file = NULL;
701 static char debug_log_file_buffer[1024];
703 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
705 if (debug_flag && mainconfig.radlog_dest == RADLOG_STDOUT) {
706 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
710 if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) != NULL)) {
711 cprintf(listener, "ERROR: Cannot direct debug logs to absolute path.\n");
714 debug_log_file = NULL;
716 if (argc == 0) return 0;
719 * This looks weird, but it's here to avoid locking
720 * a mutex for every log message.
722 memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer));
725 * Debug files always go to the logging directory.
727 snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer),
728 "%s/%s", radlog_dir, argv[0]);
730 debug_log_file = &debug_log_file_buffer[0];
735 extern char *debug_condition;
736 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
739 * Delete old condition.
741 * This is thread-safe because the condition is evaluated
742 * in the main server thread, as is this code.
744 free(debug_condition);
745 debug_condition = NULL;
754 debug_condition = strdup(argv[0]);
759 static int command_show_debug_condition(rad_listen_t *listener,
760 UNUSED int argc, UNUSED char *argv[])
762 if (!debug_condition) return 0;
764 cprintf(listener, "%s\n", debug_condition);
769 static int command_show_debug_file(rad_listen_t *listener,
770 UNUSED int argc, UNUSED char *argv[])
772 if (!debug_log_file) return 0;
774 cprintf(listener, "%s\n", debug_log_file);
779 static int command_show_debug_level(rad_listen_t *listener,
780 UNUSED int argc, UNUSED char *argv[])
782 cprintf(listener, "%d\n", debug_flag);
787 static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[])
793 cprintf(listener, "ERROR: Must specify <ipaddr>\n");
797 if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
798 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
803 client = client_find(NULL, &ipaddr);
805 cprintf(listener, "ERROR: No such client\n");
813 static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[])
818 client = get_client(listener, argc, argv);
823 if (!client->cs) return 1;
825 fp = fdopen(dup(listener->fd), "a");
827 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
831 cf_section2file(fp, client->cs);
838 static home_server *get_home_server(rad_listen_t *listener, int argc, char *argv[])
845 cprintf(listener, "ERROR: Must specify <ipaddr> <port>\n");
849 if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
850 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
855 port = atoi(argv[1]);
857 home = home_server_find(&ipaddr, port);
859 cprintf(listener, "ERROR: No such home server\n");
866 static int command_show_home_server_config(rad_listen_t *listener, int argc, char *argv[])
871 home = get_home_server(listener, argc, argv);
876 if (!home->cs) return 1;
878 fp = fdopen(dup(listener->fd), "a");
880 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
884 cf_section2file(fp, home->cs);
890 extern void revive_home_server(void *ctx);
891 extern void mark_home_server_dead(home_server *home, struct timeval *when);
893 static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
898 cprintf(listener, "ERROR: Must specify <ipaddr> <port> <state>\n");
902 home = get_home_server(listener, argc, argv);
907 if (strcmp(argv[2], "alive") == 0) {
908 revive_home_server(home);
910 } else if (strcmp(argv[2], "dead") == 0) {
913 gettimeofday(&now, NULL); /* we do this WAY too ofetn */
914 mark_home_server_dead(home, &now);
917 cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[2]);
924 static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
928 home = get_home_server(listener, argc, argv);
933 switch (home->state) {
934 case HOME_STATE_ALIVE:
935 cprintf(listener, "alive\n");
938 case HOME_STATE_IS_DEAD:
939 cprintf(listener, "dead\n");
942 case HOME_STATE_ZOMBIE:
943 cprintf(listener, "zombie\n");
947 cprintf(listener, "unknown\n");
956 static fr_command_table_t command_table_debug[] = {
957 { "condition", FR_WRITE,
958 "debug condition [condition] - Enable debugging for requests matching [condition]",
959 command_debug_condition, NULL },
962 "debug level <number> - Set debug level to <number>. Higher is more debugging.",
963 command_debug_level, NULL },
966 "debug file [filename] - Send all debugging output to [filename]",
967 command_debug_file, NULL },
969 { NULL, 0, NULL, NULL, NULL }
972 static fr_command_table_t command_table_show_debug[] = {
973 { "condition", FR_READ,
974 "show debug condition - Shows current debugging condition.",
975 command_show_debug_condition, NULL },
978 "show debug level - Shows current debugging level.",
979 command_show_debug_level, NULL },
982 "show debug file - Shows current debugging file.",
983 command_show_debug_file, NULL },
985 { NULL, 0, NULL, NULL, NULL }
988 static fr_command_table_t command_table_show_module[] = {
990 "show module config <module> - show configuration for given module",
991 command_show_module_config, NULL },
993 "show module flags <module> - show other module properties",
994 command_show_module_flags, NULL },
996 "show module list - shows list of loaded modules",
997 command_show_modules, NULL },
998 { "methods", FR_READ,
999 "show module methods <module> - show sections where <module> may be used",
1000 command_show_module_methods, NULL },
1002 { NULL, 0, NULL, NULL, NULL }
1005 static fr_command_table_t command_table_show_client[] = {
1006 { "config", FR_READ,
1007 "show client config <ipaddr> - show configuration for given client",
1008 command_show_client_config, NULL },
1010 "show client list - shows list of global clients",
1011 command_show_clients, NULL },
1013 { NULL, 0, NULL, NULL, NULL }
1017 static fr_command_table_t command_table_show_home[] = {
1018 { "config", FR_READ,
1019 "show home_server config <ipaddr> <port> - show configuration for given home server",
1020 command_show_home_server_config, NULL },
1022 "show home_server list - shows list of home servers",
1023 command_show_home_servers, NULL },
1025 "show home_server state <ipaddr> <port> - shows state of given home server",
1026 command_show_home_server_state, NULL },
1028 { NULL, 0, NULL, NULL, NULL }
1033 static fr_command_table_t command_table_show[] = {
1034 { "client", FR_READ,
1035 "show client <command> - do sub-command of client",
1036 NULL, command_table_show_client },
1038 "show debug <command> - show debug properties",
1039 NULL, command_table_show_debug },
1041 { "home_server", FR_READ,
1042 "show home_server <command> - do sub-command of home_server",
1043 NULL, command_table_show_home },
1045 { "module", FR_READ,
1046 "show module <command> - do sub-command of module",
1047 NULL, command_table_show_module },
1048 { "uptime", FR_READ,
1049 "show uptime - shows time at which server started",
1050 command_uptime, NULL },
1051 { "version", FR_READ,
1052 "show version - Prints version of the running server",
1053 command_show_version, NULL },
1055 "show xml <reference> - Prints out configuration as XML",
1056 command_show_xml, NULL },
1057 { NULL, 0, NULL, NULL, NULL }
1061 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
1066 module_instance_t *mi;
1067 const CONF_PARSER *variables;
1071 cprintf(listener, "ERROR: No module name or variable was given\n");
1075 cs = cf_section_find("modules");
1078 mi = find_module_instance(cs, argv[0], 0);
1080 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
1084 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
1085 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
1089 variables = cf_section_parse_table(mi->cs);
1091 cprintf(listener, "ERROR: Cannot find configuration for module\n");
1096 for (i = 0; variables[i].name != NULL; i++) {
1098 * FIXME: Recurse into sub-types somehow...
1100 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
1102 if (strcmp(variables[i].name, argv[1]) == 0) {
1109 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
1113 i = rcode; /* just to be safe */
1116 * It's not part of the dynamic configuration. The module
1117 * needs to re-parse && validate things.
1119 if (variables[i].data) {
1120 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
1124 data = ((char *) mi->insthandle) + variables[i].offset;
1126 cp = cf_pair_find(mi->cs, argv[1]);
1130 * Replace the OLD value in the configuration file with
1133 * FIXME: Parse argv[2] depending on it's data type!
1134 * If it's a string, look for leading single/double quotes,
1135 * end then call tokenize functions???
1137 cf_pair_replace(mi->cs, cp, argv[2]);
1139 rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
1142 cprintf(listener, "ERROR: Failed to parse value\n");
1146 return 1; /* success */
1149 static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
1152 cprintf(listener, "\trequests\t%d\n", stats->total_requests);
1153 cprintf(listener, "\tresponses\t%d\n", stats->total_responses);
1156 cprintf(listener, "\taccepts\t\t%d\n",
1157 stats->total_access_accepts);
1158 cprintf(listener, "\trejects\t\t%d\n",
1159 stats->total_access_rejects);
1160 cprintf(listener, "\tchallenges\t%d\n",
1161 stats->total_access_challenges);
1164 cprintf(listener, "\tdup\t\t%d\n", stats->total_dup_requests);
1165 cprintf(listener, "\tinvalid\t\t%d\n", stats->total_invalid_requests);
1166 cprintf(listener, "\tmalformed\t%d\n", stats->total_malformed_requests);
1167 cprintf(listener, "\tbad_signature\t%d\n", stats->total_bad_authenticators);
1168 cprintf(listener, "\tdropped\t\t%d\n", stats->total_packets_dropped);
1169 cprintf(listener, "\tunknown_types\t%d\n", stats->total_unknown_types);
1176 static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
1181 cprintf(listener, "ERROR: Must specify [auth/acct] OR <ipaddr> <port>\n");
1186 #ifdef WITH_ACCOUNTING
1187 if (strcmp(argv[0], "acct") == 0) {
1188 return command_print_stats(listener,
1189 &proxy_acct_stats, 0);
1192 if (strcmp(argv[0], "auth") == 0) {
1193 return command_print_stats(listener,
1194 &proxy_auth_stats, 1);
1197 cprintf(listener, "ERROR: Should specify [auth/acct]\n");
1201 home = get_home_server(listener, argc, argv);
1206 command_print_stats(listener, &home->stats,
1207 (home->type == HOME_TYPE_AUTH));
1208 cprintf(listener, "\toutstanding\t%d\n", home->currently_outstanding);
1213 static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
1219 cprintf(listener, "ERROR: Must specify [auth/acct]\n");
1223 if (strcmp(argv[0], "auth") == 0) {
1226 } else if (strcmp(argv[0], "acct") == 0) {
1227 #ifdef WITH_ACCOUNTING
1230 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1235 cprintf(listener, "ERROR: Unknown statistics type\n");
1240 * Global results for all client.
1243 #ifdef WITH_ACCOUNTING
1245 return command_print_stats(listener,
1246 &radius_acct_stats, auth);
1249 return command_print_stats(listener, &radius_auth_stats, auth);
1252 client = get_client(listener, argc - 1, argv + 1);
1257 #ifdef WITH_ACCOUNTING
1259 return command_print_stats(listener, client->acct, auth);
1263 return command_print_stats(listener, client->auth, auth);
1267 static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
1272 cprintf(listener, "ERROR: <file> is required\n");
1277 * Read the file and generate the client.
1279 c = client_read(argv[0], FALSE, FALSE);
1281 cprintf(listener, "ERROR: Unknown error reading client file.\n");
1285 if (!client_add(NULL, c)) {
1286 cprintf(listener, "ERROR: Unknown error inserting new client.\n");
1295 static fr_command_table_t command_table_add_client[] = {
1297 "add client file <filename> - Add new client definition from <filename>",
1298 command_add_client_file, NULL },
1300 { NULL, 0, NULL, NULL, NULL }
1304 static fr_command_table_t command_table_add[] = {
1305 { "client", FR_WRITE,
1306 "add client <command> - Add client configuration commands",
1307 NULL, command_table_add_client },
1309 { NULL, 0, NULL, NULL, NULL }
1314 static fr_command_table_t command_table_set_home[] = {
1315 { "state", FR_WRITE,
1316 "set home_server state <ipaddr> <port> [alive|dead] - set state for given home server",
1317 command_set_home_server_state, NULL },
1319 { NULL, 0, NULL, NULL, NULL }
1323 static fr_command_table_t command_table_set_module[] = {
1324 { "config", FR_WRITE,
1325 "set module config <module> variable value - set configuration for <module>",
1326 command_set_module_config, NULL },
1328 { NULL, 0, NULL, NULL, NULL }
1332 static fr_command_table_t command_table_set[] = {
1333 { "module", FR_WRITE,
1334 "set module <command> - set module commands",
1335 NULL, command_table_set_module },
1337 { "home_server", FR_WRITE,
1338 "set home_server <command> - set home server commands",
1339 NULL, command_table_set_home },
1342 { NULL, 0, NULL, NULL, NULL }
1346 static fr_command_table_t command_table_stats[] = {
1347 { "client", FR_READ,
1348 "stats client [auth/acct] <ipaddr> - show statistics for client",
1349 command_stats_client, NULL },
1351 { "home_server", FR_READ,
1352 "stats home_server <ipaddr> <port> - show statistics for home server",
1353 command_stats_home_server, NULL },
1356 { NULL, 0, NULL, NULL, NULL }
1359 static fr_command_table_t command_table[] = {
1360 { "add", FR_WRITE, NULL, NULL, command_table_add },
1361 { "debug", FR_WRITE,
1362 "debug <command> - debugging commands",
1363 NULL, command_table_debug },
1365 "hup [module] - sends a HUP signal to the server, or optionally to one module",
1366 command_hup, NULL },
1367 { "reconnect", FR_READ,
1368 "reconnect - reconnect to a running server",
1369 NULL, NULL }, /* just here for "help" */
1370 { "terminate", FR_WRITE,
1371 "terminate - terminates the server, and cause it to exit",
1372 command_terminate, NULL },
1373 { "set", FR_WRITE, NULL, NULL, command_table_set },
1374 { "show", FR_READ, NULL, NULL, command_table_show },
1375 { "stats", FR_READ, NULL, NULL, command_table_stats },
1377 { NULL, 0, NULL, NULL, NULL }
1382 * Parse the unix domain sockets.
1384 * FIXME: TCP + SSL, after RadSec is in.
1386 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
1388 fr_command_socket_t *sock;
1392 if (cf_section_parse(cs, sock, command_config) < 0) {
1396 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
1397 if (sock->uid_name) {
1400 pw = getpwnam(sock->uid_name);
1402 radlog(L_ERR, "Failed getting uid for %s: %s",
1403 sock->uid_name, strerror(errno));
1407 sock->uid = pw->pw_uid;
1410 if (sock->gid_name) {
1413 gr = getgrnam(sock->gid_name);
1415 radlog(L_ERR, "Failed getting gid for %s: %s",
1416 sock->gid_name, strerror(errno));
1419 sock->gid = gr->gr_gid;
1422 #else /* can't get uid or gid of connecting user */
1424 if (sock->uid_name || sock->gid_name) {
1425 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
1431 if (!sock->mode_name) {
1432 sock->mode = FR_READ;
1434 sock->mode = fr_str2int(mode_names, sock->mode_name, 0);
1436 radlog(L_ERR, "Invalid mode name \"%s\"",
1443 * FIXME: check for absolute pathnames?
1444 * check for uid/gid on the other end...
1447 this->fd = fr_server_domain_socket(sock->path);
1455 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
1457 fr_command_socket_t *sock = this->data;
1459 snprintf(buffer, bufsize, "command file %s", sock->path);
1465 * String split routine. Splits an input string IN PLACE
1466 * into pieces, based on spaces.
1468 static int str2argv(char *str, char **argv, int max_argc)
1475 if (argc >= max_argc) return argc;
1478 * Chop out comments early.
1485 while ((*str == ' ') ||
1488 (*str == '\n')) *(str++) = '\0';
1490 if (!*str) return argc;
1492 if ((*str == '\'') || (*str == '"')) {
1496 token = gettoken((const char **) &p, buffer,
1498 if ((token != T_SINGLE_QUOTED_STRING) &&
1499 (token != T_DOUBLE_QUOTED_STRING)) {
1503 len = strlen(buffer);
1504 if (len >= (size_t) (p - str)) {
1508 memcpy(str, buffer, len + 1);
1521 (*str != '\n')) str++;
1527 static void print_help(rad_listen_t *listener,
1528 fr_command_table_t *table, int recursive)
1532 for (i = 0; table[i].command != NULL; i++) {
1533 if (table[i].help) {
1534 cprintf(listener, "%s\n",
1537 cprintf(listener, "%s <command> - do sub-command of %s\n",
1538 table[i].command, table[i].command);
1541 if (recursive && table[i].table) {
1542 print_help(listener, table[i].table, recursive);
1547 #define MAX_ARGV (16)
1550 * Check if an incoming request is "ok"
1552 * It takes packets, not requests. It sees if the packet looks
1553 * OK. If so, it does a number of sanity checks on it.
1555 static int command_domain_recv(rad_listen_t *listener,
1556 UNUSED RAD_REQUEST_FUNP *pfun,
1557 UNUSED REQUEST **prequest)
1562 char *my_argv[MAX_ARGV], **argv;
1563 fr_command_table_t *table;
1564 fr_command_socket_t *co = listener->data;
1573 len = recv(listener->fd, co->buffer + co->offset,
1574 sizeof(co->buffer) - co->offset - 1, 0);
1575 if (len == 0) goto close_socket; /* clean close */
1578 if ((errno == EAGAIN) || (errno == EINTR)) {
1587 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1589 command_close_socket(listener);
1594 * See if there are multiple lines in the buffer.
1596 p = co->buffer + co->offset;
1599 for (c = 0; c < len; c++) {
1600 if ((*p == '\r') || (*p == '\n')) {
1605 * FIXME: do real buffering...
1606 * handling of CTRL-C, etc.
1611 * \r \n followed by ASCII...
1622 * Saw CR/LF. Set next element, and exit.
1625 co->next = p - co->buffer;
1629 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1630 radlog(L_ERR, "Line too long!");
1637 argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1638 if (argc == 0) goto do_next; /* empty strings are OK */
1641 cprintf(listener, "ERROR: Failed parsing command.\n");
1647 for (len = 0; len <= co->offset; len++) {
1648 if (co->buffer[len] < 0x20) {
1649 co->buffer[len] = '\0';
1655 * Hard-code exit && quit.
1657 if ((strcmp(argv[0], "exit") == 0) ||
1658 (strcmp(argv[0], "quit") == 0)) goto close_socket;
1662 if (strcmp(argv[0], "login") != 0) {
1663 cprintf(listener, "ERROR: Login required\n");
1668 cprintf(listener, "ERROR: login <user> <password>\n");
1673 * FIXME: Generate && process fake RADIUS request.
1675 if ((strcmp(argv[1], "root") == 0) &&
1676 (strcmp(argv[2], "password") == 0)) {
1677 strlcpy(co->user, argv[1], sizeof(co->user));
1681 cprintf(listener, "ERROR: Login incorrect\n");
1686 table = command_table;
1689 for (i = 0; table[i].command != NULL; i++) {
1690 if (strcmp(table[i].command, argv[0]) == 0) {
1692 * Check permissions.
1694 if (((co->mode & FR_WRITE) == 0) &&
1695 ((table[i].mode & FR_WRITE) != 0)) {
1696 cprintf(listener, "ERROR: You do not have write permission.\n");
1700 if (table[i].table) {
1702 * This is the last argument, but
1703 * there's a sub-table. Print help.
1707 table = table[i].table;
1713 table = table[i].table;
1717 if (!table[i].func) {
1718 cprintf(listener, "ERROR: Invalid command\n");
1723 rcode = table[i].func(listener,
1724 argc - 1, argv + 1);
1733 if ((strcmp(argv[0], "help") == 0) ||
1734 (strcmp(argv[0], "?") == 0)) {
1738 if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
1742 print_help(listener, table, recursive);
1746 cprintf(listener, "ERROR: Unknown command \"%s\"\n",
1751 cprintf(listener, "radmin> ");
1753 if (co->next <= co->offset) {
1756 memmove(co->buffer, co->buffer + co->next,
1757 co->offset - co->next);
1758 co->offset -= co->next;
1765 static int command_domain_accept(rad_listen_t *listener,
1766 UNUSED RAD_REQUEST_FUNP *pfun,
1767 UNUSED REQUEST **prequest)
1773 struct sockaddr_storage src;
1774 fr_command_socket_t *sock = listener->data;
1776 salen = sizeof(src);
1778 DEBUG2(" ... new connection request on command socket.");
1780 newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
1783 * Non-blocking sockets must handle this.
1785 if (errno == EWOULDBLOCK) {
1789 DEBUG2(" ... failed to accept connection.");
1794 * Perform user authentication.
1796 if (sock->uid_name || sock->gid_name) {
1800 if (getpeereid(listener->fd, &uid, &gid) < 0) {
1801 radlog(L_ERR, "Failed getting peer credentials for %s: %s",
1802 sock->path, strerror(errno));
1807 if (sock->uid_name && (sock->uid != uid)) {
1808 radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
1809 sock->path, (long int) uid);
1814 if (sock->gid_name && (sock->gid != gid)) {
1815 radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
1816 sock->path, (long int) gid);
1823 * Write 32-bit magic number && version information.
1825 magic = htonl(0xf7eead15);
1826 if (write(newfd, &magic, 4) < 0) {
1827 radlog(L_ERR, "Failed writing initial data to socket: %s",
1832 magic = htonl(1); /* protocol version */
1833 if (write(newfd, &magic, 4) < 0) {
1834 radlog(L_ERR, "Failed writing initial data to socket: %s",
1842 * Add the new listener.
1844 this = listen_alloc(listener->type);
1845 if (!this) return -1;
1848 * Copy everything, including the pointer to the socket
1852 memcpy(this, listener, sizeof(*this));
1853 this->status = RAD_LISTEN_STATUS_INIT;
1855 this->data = sock; /* fix it back */
1858 sock->user[0] = '\0';
1859 sock->path = ((fr_command_socket_t *) listener->data)->path;
1860 sock->mode = ((fr_command_socket_t *) listener->data)->mode;
1863 this->recv = command_domain_recv;
1866 * Tell the event loop that we have a new FD
1875 * Send an authentication response packet
1877 static int command_domain_send(UNUSED rad_listen_t *listener,
1878 UNUSED REQUEST *request)
1884 static int command_socket_encode(UNUSED rad_listen_t *listener,
1885 UNUSED REQUEST *request)
1891 static int command_socket_decode(UNUSED rad_listen_t *listener,
1892 UNUSED REQUEST *request)
1897 #endif /* WITH_COMMAND_SOCKET */