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>
35 #ifdef HAVE_SYS_STAT_H
47 typedef struct fr_command_table_t fr_command_table_t;
49 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
54 struct fr_command_table_t {
56 int mode; /* read/write */
58 fr_command_func_t func;
59 fr_command_table_t *table;
62 #define COMMAND_BUFFER_SIZE (1024)
64 typedef struct fr_command_socket_t {
75 char buffer[COMMAND_BUFFER_SIZE];
76 } fr_command_socket_t;
78 static const CONF_PARSER command_config[] = {
79 { "socket", PW_TYPE_STRING_PTR,
80 offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
81 { "uid", PW_TYPE_STRING_PTR,
82 offsetof(fr_command_socket_t, uid_name), NULL, NULL},
83 { "gid", PW_TYPE_STRING_PTR,
84 offsetof(fr_command_socket_t, gid_name), NULL, NULL},
85 { "mode", PW_TYPE_STRING_PTR,
86 offsetof(fr_command_socket_t, mode_name), NULL, NULL},
88 { NULL, -1, 0, NULL, NULL } /* end the list */
91 static FR_NAME_NUMBER mode_names[] = {
93 { "read-only", FR_READ },
94 { "read-write", FR_READ | FR_WRITE },
95 { "rw", FR_READ | FR_WRITE },
100 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
102 __attribute__ ((format (printf, 2, 3)))
106 #ifndef HAVE_GETPEEREID
107 static int getpeereid(int s, uid_t *euid, gid_t *egid)
113 socklen_t cl = sizeof(cr);
115 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
122 #endif /* SO_PEERCRED */
124 #endif /* HAVE_GETPEEREID */
127 static int fr_server_domain_socket(const char *path)
132 struct sockaddr_un salocal;
136 if (len >= sizeof(salocal.sun_path)) {
137 radlog(L_ERR, "Path too long in socket filename.");
141 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
142 radlog(L_ERR, "Failed creating socket: %s",
147 memset(&salocal, 0, sizeof(salocal));
148 salocal.sun_family = AF_UNIX;
149 memcpy(salocal.sun_path, path, len); /* not zero terminated */
151 socklen = sizeof(salocal.sun_family) + len;
156 if (stat(path, &buf) < 0) {
157 if (errno != ENOENT) {
158 radlog(L_ERR, "Failed to stat %s: %s",
159 path, strerror(errno));
164 * FIXME: Check the enclosing directory?
166 } else { /* it exists */
167 if (!S_ISREG(buf.st_mode)
169 && !S_ISSOCK(buf.st_mode)
172 radlog(L_ERR, "Cannot turn %s into socket", path);
177 * Refuse to open sockets not owned by us.
179 if (buf.st_uid != geteuid()) {
180 radlog(L_ERR, "We do not own %s", path);
184 if (unlink(path) < 0) {
185 radlog(L_ERR, "Failed to delete %s: %s",
186 path, strerror(errno));
191 if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
192 radlog(L_ERR, "Failed binding to %s: %s",
193 path, strerror(errno));
199 * FIXME: There's a race condition here. But Linux
200 * doesn't seem to permit fchmod on domain sockets.
202 if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
203 radlog(L_ERR, "Failed setting permissions on %s: %s",
204 path, strerror(errno));
209 if (listen(sockfd, 8) < 0) {
210 radlog(L_ERR, "Failed listening to %s: %s",
211 path, strerror(errno));
220 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
221 radlog(L_ERR, "Failure getting socket flags: %s",
228 if( fcntl(sockfd, F_SETFL, flags) < 0) {
229 radlog(L_ERR, "Failure setting socket flags: %s",
241 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
248 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
251 if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0;
253 len = write(listener->fd, buffer, len);
255 listener->status = RAD_LISTEN_STATUS_CLOSED;
256 event_new_fd(listener);
260 * FIXME: Keep writing until done?
265 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
268 module_instance_t *mi;
271 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
275 cs = cf_section_find("modules");
278 mi = find_module_instance(cs, argv[0], 0);
280 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
284 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
285 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
290 if (!module_hup_module(mi->cs, mi, time(NULL))) {
291 cprintf(listener, "ERROR: Failed to reload module\n");
295 return 1; /* success */
298 static int command_terminate(UNUSED rad_listen_t *listener,
299 UNUSED int argc, UNUSED char *argv[])
301 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
303 return 1; /* success */
306 extern time_t fr_start_time;
308 static int command_uptime(rad_listen_t *listener,
309 UNUSED int argc, UNUSED char *argv[])
313 CTIME_R(&fr_start_time, buffer, sizeof(buffer));
314 cprintf(listener, "Up since %s", buffer); /* no \r\n */
316 return 1; /* success */
319 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";
322 * FIXME: Recurse && indent?
324 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
330 const char *name1 = cf_section_name1(cs);
331 const char *name2 = cf_section_name2(cs);
332 const CONF_PARSER *variables = cf_section_parse_table(cs);
336 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
338 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
346 if (variables) for (i = 0; variables[i].name != NULL; i++) {
348 * No base struct offset, data must be the pointer.
349 * If data doesn't exist, ignore the entry, there
350 * must be something wrong.
353 if (!variables[i].data) {
357 data = variables[i].data;;
359 } else if (variables[i].data) {
360 data = variables[i].data;;
363 data = (((char *)base) + variables[i].offset);
366 switch (variables[i].type) {
368 cprintf(listener, "%.*s%s = ?\n", indent, tabs,
372 case PW_TYPE_INTEGER:
373 cprintf(listener, "%.*s%s = %u\n", indent, tabs,
374 variables[i].name, *(int *) data);
378 inet_ntop(AF_INET, data, buffer, sizeof(buffer));
381 case PW_TYPE_IPV6ADDR:
382 inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
385 case PW_TYPE_BOOLEAN:
386 cprintf(listener, "%.*s%s = %s\n", indent, tabs,
388 ((*(int *) data) == 0) ? "no" : "yes");
391 case PW_TYPE_STRING_PTR:
392 case PW_TYPE_FILENAME:
394 * FIXME: Escape things in the string!
396 if (*(char **) data) {
397 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
398 variables[i].name, *(char **) data);
400 cprintf(listener, "%.*s%s = \n", indent, tabs,
410 cprintf(listener, "%.*s}\n", indent, tabs);
413 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
416 module_instance_t *mi;
419 cprintf(listener, "ERROR: No module name was given\n");
423 cs = cf_section_find("modules");
426 mi = find_module_instance(cs, argv[0], 0);
428 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
432 cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
434 return 1; /* success */
437 static const char *method_names[RLM_COMPONENT_COUNT] = {
449 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
453 const module_instance_t *mi;
457 cprintf(listener, "ERROR: No module name was given\n");
461 cs = cf_section_find("modules");
464 mi = find_module_instance(cs, argv[0], 0);
466 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
470 mod = mi->entry->module;
472 for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
473 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
476 return 1; /* success */
480 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
483 const module_instance_t *mi;
487 cprintf(listener, "ERROR: No module name was given\n");
491 cs = cf_section_find("modules");
494 mi = find_module_instance(cs, argv[0], 0);
496 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
500 mod = mi->entry->module;
502 if ((mod->type & RLM_TYPE_THREAD_SAFE) != 0)
503 cprintf(listener, "\tthread-safe\n");
506 if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
507 cprintf(listener, "\twill-check-config\n");
510 if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
511 cprintf(listener, "\treload-on-hup\n");
513 return 1; /* success */
518 * Show all loaded modules
520 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
522 CONF_SECTION *cs, *subcs;
524 cs = cf_section_find("modules");
528 while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
529 const char *name1 = cf_section_name1(subcs);
530 const char *name2 = cf_section_name2(subcs);
532 module_instance_t *mi;
535 mi = find_module_instance(cs, name2, 0);
538 cprintf(listener, "\t%s (%s)\n", name2, name1);
540 mi = find_module_instance(cs, name1, 0);
543 cprintf(listener, "\t%s\n", name1);
547 return 1; /* success */
550 static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
556 for (i = 0; i < 256; i++) {
557 home = home_server_bynumber(i);
561 * Internal "virtual" home server.
563 if (home->ipaddr.af == AF_UNSPEC) continue;
565 cprintf(listener, "\t%s\t%d\n",
566 ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
574 static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
580 for (i = 0; i < 256; i++) {
581 client = client_findbynumber(NULL, i);
584 ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
586 if (((client->ipaddr.af == AF_INET) &&
587 (client->prefix != 32)) ||
588 ((client->ipaddr.af == AF_INET6) &&
589 (client->prefix != 128))) {
590 cprintf(listener, "\t%s/%d\n", buffer, client->prefix);
592 cprintf(listener, "\t%s\n", buffer);
600 static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
603 FILE *fp = fdopen(dup(listener->fd), "a");
606 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
611 cprintf(listener, "ERROR: <reference> is required\n");
615 ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
617 cprintf(listener, "ERROR: No such item <reference>\n");
621 if (cf_item_is_section(ci)) {
622 cf_section2xml(fp, cf_itemtosection(ci));
624 } else if (cf_item_is_pair(ci)) {
625 cf_pair2xml(fp, cf_itemtopair(ci));
628 cprintf(listener, "ERROR: No such item <reference>\n");
635 return 1; /* success */
638 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
643 cprintf(listener, "ERROR: Must specify <number>\n");
647 number = atoi(argv[0]);
648 if ((number < 0) || (number > 4)) {
649 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
653 fr_debug_flag = debug_flag = number;
658 extern char *debug_log_file;
659 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
662 cprintf(listener, "ERROR: Must specify <filename>\n");
666 if (debug_flag && mainconfig.radlog_dest == RADLOG_STDOUT) {
667 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
671 if (debug_log_file) {
672 free(debug_log_file);
673 debug_log_file = NULL;
675 debug_log_file = strdup(argv[0]);
680 extern char *debug_condition;
681 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
684 * Delete old condition.
686 * This is thread-safe because the condition is evaluated
687 * in the main server thread, as is this code.
689 free(debug_condition);
690 debug_condition = NULL;
699 debug_condition = strdup(argv[0]);
704 static int command_show_debug_condition(rad_listen_t *listener,
705 UNUSED int argc, UNUSED char *argv[])
707 if (!debug_condition) return 0;
709 cprintf(listener, "%s\n", debug_condition);
714 static int command_show_debug_file(rad_listen_t *listener,
715 UNUSED int argc, UNUSED char *argv[])
717 if (!debug_log_file) return 0;
719 cprintf(listener, "%s\n", debug_log_file);
724 static int command_show_debug_level(rad_listen_t *listener,
725 UNUSED int argc, UNUSED char *argv[])
727 cprintf(listener, "%d\n", debug_flag);
732 static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[])
739 cprintf(listener, "ERROR: Must specify <ipaddr>\n");
743 if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
744 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
749 client = client_find(NULL, &ipaddr);
751 cprintf(listener, "ERROR: No such client\n");
755 if (!client->cs) return 1;
757 fp = fdopen(dup(listener->fd), "a");
759 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
763 cf_section2file(fp, client->cs);
769 static int command_show_home_server_config(rad_listen_t *listener, int argc, char *argv[])
777 cprintf(listener, "ERROR: Must specify <ipaddr> <port>\n");
781 if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
782 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
787 port = atoi(argv[1]);
789 home = home_server_find(&ipaddr, port);
791 cprintf(listener, "ERROR: No such home server\n");
795 if (!home->cs) return 1;
797 fp = fdopen(dup(listener->fd), "a");
799 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
803 cf_section2file(fp, home->cs);
811 static fr_command_table_t command_table_debug[] = {
812 { "condition", FR_WRITE,
813 "debug condition <condition> - Enable debugging for requests matching <condition>",
814 command_debug_condition, NULL },
817 "debug level <number> - Set debug level to <number>. Higher is more debugging.",
818 command_debug_level, NULL },
821 "debug file <filename> - Send all debuggin output to <filename>",
822 command_debug_file, NULL },
824 { NULL, 0, NULL, NULL, NULL }
827 static fr_command_table_t command_table_show_debug[] = {
828 { "condition", FR_READ,
829 "show debug condition - Shows current debugging condition.",
830 command_show_debug_condition, NULL },
833 "show debug level - Shows current debugging level.",
834 command_show_debug_level, NULL },
837 "show debug file - Shows current debugging file.",
838 command_show_debug_file, NULL },
840 { NULL, 0, NULL, NULL, NULL }
843 static fr_command_table_t command_table_show_module[] = {
845 "show module config <module> - show configuration for given module",
846 command_show_module_config, NULL },
848 "show module flags <module> - show other module properties",
849 command_show_module_flags, NULL },
851 "show module list - shows list of loaded modules",
852 command_show_modules, NULL },
853 { "methods", FR_READ,
854 "show module methods <module> - show sections where <module> may be used",
855 command_show_module_methods, NULL },
857 { NULL, 0, NULL, NULL, NULL }
860 static fr_command_table_t command_table_show_client[] = {
862 "show client config <ipaddr> - show configuration for given client",
863 command_show_client_config, NULL },
865 "show client list - shows list of global clients",
866 command_show_clients, NULL },
868 { NULL, 0, NULL, NULL, NULL }
871 static fr_command_table_t command_table_show_home[] = {
873 "show home_server config <ipaddr> <port> - show configuration for given home server",
874 command_show_home_server_config, NULL },
876 "show home_server list - shows list of home servers",
877 command_show_home_servers, NULL },
879 { NULL, 0, NULL, NULL, NULL }
883 static fr_command_table_t command_table_show[] = {
885 "show client <command> - do sub-command of client",
886 NULL, command_table_show_client },
888 "show debug <command> - show debug properties",
889 NULL, command_table_show_debug },
890 { "home_server", FR_READ,
891 "show home_server <command> - do sub-command of home_server",
892 NULL, command_table_show_home },
894 "show module <command> - do sub-command of module",
895 NULL, command_table_show_module },
897 "show uptime - shows time at which server started",
898 command_uptime, NULL },
900 "show xml <reference> - Prints out configuration as XML",
901 command_show_xml, NULL },
902 { NULL, 0, NULL, NULL, NULL }
906 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
911 module_instance_t *mi;
912 const CONF_PARSER *variables;
916 cprintf(listener, "ERROR: No module name or variable was given\n");
920 cs = cf_section_find("modules");
923 mi = find_module_instance(cs, argv[0], 0);
925 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
929 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
930 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
934 variables = cf_section_parse_table(mi->cs);
936 cprintf(listener, "ERROR: Cannot find configuration for module\n");
941 for (i = 0; variables[i].name != NULL; i++) {
943 * FIXME: Recurse into sub-types somehow...
945 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
947 if (strcmp(variables[i].name, argv[1]) == 0) {
954 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
958 i = rcode; /* just to be safe */
961 * It's not part of the dynamic configuration. The module
962 * needs to re-parse && validate things.
964 if (variables[i].data) {
965 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
969 data = ((char *) mi->insthandle) + variables[i].offset;
971 cp = cf_pair_find(mi->cs, argv[1]);
975 * Replace the OLD value in the configuration file with
978 * FIXME: Parse argv[2] depending on it's data type!
979 * If it's a string, look for leading single/double quotes,
980 * end then call tokenize functions???
982 cf_pair_replace(mi->cs, cp, argv[2]);
984 rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
987 cprintf(listener, "ERROR: Failed to parse value\n");
991 return 1; /* success */
994 static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
997 cprintf(listener, "\trequests\t%d\n", stats->total_requests);
998 cprintf(listener, "\tresponses\t%d\n", stats->total_responses);
1001 cprintf(listener, "\taccepts\t\t%d\n",
1002 stats->total_access_accepts);
1003 cprintf(listener, "\trejects\t\t%d\n",
1004 stats->total_access_rejects);
1005 cprintf(listener, "\tchallenges\t%d\n",
1006 stats->total_access_challenges);
1009 cprintf(listener, "\tdup\t\t%d\n", stats->total_dup_requests);
1010 cprintf(listener, "\tinvalid\t\t%d\n", stats->total_invalid_requests);
1011 cprintf(listener, "\tmalformed\t%d\n", stats->total_malformed_requests);
1012 cprintf(listener, "\tbad_signature\t%d\n", stats->total_bad_authenticators);
1013 cprintf(listener, "\tdropped\t\t%d\n", stats->total_packets_dropped);
1014 cprintf(listener, "\tunknown_types\t%d\n", stats->total_unknown_types);
1020 static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
1027 cprintf(listener, "ERROR: <ipaddr> and <port> are required.\n");
1031 if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
1032 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1037 port = atoi(argv[1]);
1039 home = home_server_find(&ipaddr, port);
1041 cprintf(listener, "ERROR: No such home server\n");
1045 return command_print_stats(listener, &home->stats,
1046 (home->type == HOME_TYPE_AUTH));
1050 static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
1057 return command_print_stats(listener, &radius_auth_stats, 1);
1060 if (strcmp(argv[0], "auth") == 0) {
1063 } else if (strcmp(argv[0], "acct") == 0) {
1064 #ifdef WITH_ACCOUNTING
1067 cprintf(listener, "ERROR: This server was built without accounting support.\n");
1072 cprintf(listener, "ERROR: Unknown statistics type\n");
1077 #ifdef WITH_ACCOUNTING
1079 return command_print_stats(listener,
1080 &radius_acct_stats, auth);
1083 return command_print_stats(listener, &radius_auth_stats, auth);
1086 if (ip_hton(argv[1], AF_UNSPEC, &ipaddr) < 0) {
1087 cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
1092 client = client_find(NULL, &ipaddr);
1094 cprintf(listener, "ERROR: No such client\n");
1098 #ifdef WITH_ACCOUNTING
1100 return command_print_stats(listener, client->acct, auth);
1104 return command_print_stats(listener, client->auth, auth);
1108 static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
1113 cprintf(listener, "ERROR: <file> is required\n");
1118 * Read the file and generate the client.
1120 c = client_read(argv[0], FALSE, FALSE);
1122 cprintf(listener, "ERROR: Unknown error reading client file.\n");
1126 if (!client_add(NULL, c)) {
1127 cprintf(listener, "ERROR: Unknown error inserting new client.\n");
1136 static fr_command_table_t command_table_add_client[] = {
1138 "add client file <filename> - Add new client definition from <filename>",
1139 command_add_client_file, NULL },
1141 { NULL, 0, NULL, NULL, NULL }
1145 static fr_command_table_t command_table_add[] = {
1146 { "client", FR_WRITE, NULL, NULL, command_table_add_client },
1148 { NULL, 0, NULL, NULL, NULL }
1151 static fr_command_table_t command_table_set_module[] = {
1152 { "config", FR_WRITE,
1153 "set module config <module> variable value - set configuration for <module>",
1154 command_set_module_config, NULL },
1156 { NULL, 0, NULL, NULL, NULL }
1160 static fr_command_table_t command_table_set[] = {
1161 { "module", FR_WRITE, NULL, NULL, command_table_set_module },
1163 { NULL, 0, NULL, NULL, NULL }
1167 static fr_command_table_t command_table_stats[] = {
1168 { "client", FR_READ,
1169 "stats client [auth/acct] <ipaddr> - show statistics for client",
1170 command_stats_client, NULL },
1171 { "home_server", FR_READ,
1172 "stats home_server <ipaddr> <port> - show statistics for home server",
1173 command_stats_home_server, NULL },
1175 { NULL, 0, NULL, NULL, NULL }
1178 static fr_command_table_t command_table[] = {
1179 { "add", FR_WRITE, NULL, NULL, command_table_add },
1180 { "debug", FR_WRITE,
1181 "debug <command> - debugging commands",
1182 NULL, command_table_debug },
1184 "hup [module] - sends a HUP signal to the server, or optionally to one module",
1185 command_hup, NULL },
1186 { "reconnect", FR_READ,
1187 "reconnect - reconnect to a running server",
1188 NULL, NULL }, /* just here for "help" */
1189 { "terminate", FR_WRITE,
1190 "terminate - terminates the server, and causes it to exit",
1191 command_terminate, NULL },
1192 { "set", FR_WRITE, NULL, NULL, command_table_set },
1193 { "show", FR_READ, NULL, NULL, command_table_show },
1194 { "stats", FR_READ, NULL, NULL, command_table_stats },
1196 { NULL, 0, NULL, NULL, NULL }
1201 * Parse the unix domain sockets.
1203 * FIXME: TCP + SSL, after RadSec is in.
1205 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
1207 fr_command_socket_t *sock;
1211 if (cf_section_parse(cs, sock, command_config) < 0) {
1215 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
1216 if (sock->uid_name) {
1219 pw = getpwnam(sock->uid_name);
1221 radlog(L_ERR, "Failed getting uid for %s: %s",
1222 sock->uid_name, strerror(errno));
1226 sock->uid = pw->pw_uid;
1229 if (sock->gid_name) {
1232 gr = getgrnam(sock->gid_name);
1234 radlog(L_ERR, "Failed getting gid for %s: %s",
1235 sock->gid_name, strerror(errno));
1238 sock->gid = gr->gr_gid;
1241 #else /* can't get uid or gid of connecting user */
1243 if (sock->uid_name || sock->gid_name) {
1244 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
1250 if (!sock->mode_name) {
1251 sock->mode = FR_READ;
1253 sock->mode = fr_str2int(mode_names, sock->mode_name, 0);
1255 radlog(L_ERR, "Invalid mode name \"%s\"",
1262 * FIXME: check for absolute pathnames?
1263 * check for uid/gid on the other end...
1266 this->fd = fr_server_domain_socket(sock->path);
1274 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
1276 fr_command_socket_t *sock = this->data;
1278 snprintf(buffer, bufsize, "command file %s", sock->path);
1284 * String split routine. Splits an input string IN PLACE
1285 * into pieces, based on spaces.
1287 static int str2argv(char *str, char **argv, int max_argc)
1294 if (argc >= max_argc) return argc;
1297 * Chop out comments early.
1304 while ((*str == ' ') ||
1307 (*str == '\n')) *(str++) = '\0';
1309 if (!*str) return argc;
1311 if ((*str == '\'') || (*str == '"')) {
1315 token = gettoken((const char **) &p, buffer,
1317 if ((token != T_SINGLE_QUOTED_STRING) &&
1318 (token != T_DOUBLE_QUOTED_STRING)) {
1322 len = strlen(buffer);
1323 if (len >= (size_t) (p - str)) {
1327 memcpy(str, buffer, len + 1);
1340 (*str != '\n')) str++;
1346 #define MAX_ARGV (16)
1349 * Check if an incoming request is "ok"
1351 * It takes packets, not requests. It sees if the packet looks
1352 * OK. If so, it does a number of sanity checks on it.
1354 static int command_domain_recv(rad_listen_t *listener,
1355 UNUSED RAD_REQUEST_FUNP *pfun,
1356 UNUSED REQUEST **prequest)
1361 char *my_argv[MAX_ARGV], **argv;
1362 fr_command_table_t *table;
1363 fr_command_socket_t *co = listener->data;
1372 len = recv(listener->fd, co->buffer + co->offset,
1373 sizeof(co->buffer) - co->offset - 1, 0);
1374 if (len == 0) goto close_socket; /* clean close */
1377 if ((errno == EAGAIN) || (errno == EINTR)) {
1386 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1388 listener->status = RAD_LISTEN_STATUS_CLOSED;
1389 event_new_fd(listener);
1394 * See if there are multiple lines in the buffer.
1396 p = co->buffer + co->offset;
1399 for (c = 0; c < len; c++) {
1400 if ((*p == '\r') || (*p == '\n')) {
1405 * FIXME: do real buffering...
1406 * handling of CTRL-C, etc.
1411 * \r \n followed by ASCII...
1422 * Saw CR/LF. Set next element, and exit.
1425 co->next = p - co->buffer;
1429 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1430 radlog(L_ERR, "Line too long!");
1437 argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1438 if (argc == 0) goto do_next; /* empty strings are OK */
1441 cprintf(listener, "ERROR: Failed parsing command.\n");
1447 for (len = 0; len <= co->offset; len++) {
1448 if (co->buffer[len] < 0x20) {
1449 co->buffer[len] = '\0';
1455 * Hard-code exit && quit.
1457 if ((strcmp(argv[0], "exit") == 0) ||
1458 (strcmp(argv[0], "quit") == 0)) goto close_socket;
1462 if (strcmp(argv[0], "login") != 0) {
1463 cprintf(listener, "ERROR: Login required\n");
1468 cprintf(listener, "ERROR: login <user> <password>\n");
1473 * FIXME: Generate && process fake RADIUS request.
1475 if ((strcmp(argv[1], "root") == 0) &&
1476 (strcmp(argv[2], "password") == 0)) {
1477 strlcpy(co->user, argv[1], sizeof(co->user));
1481 cprintf(listener, "ERROR: Login incorrect\n");
1486 table = command_table;
1489 for (i = 0; table[i].command != NULL; i++) {
1490 if (strcmp(table[i].command, argv[0]) == 0) {
1492 * Check permissions.
1494 if (((co->mode & FR_WRITE) == 0) &&
1495 ((table[i].mode & FR_WRITE) != 0)) {
1496 cprintf(listener, "ERROR: You do not have write permission.\n");
1500 if (table[i].table) {
1502 * This is the last argument, but
1503 * there's a sub-table. Print help.
1507 table = table[i].table;
1513 table = table[i].table;
1517 if (!table[i].func) {
1518 cprintf(listener, "ERROR: Invalid command\n");
1523 rcode = table[i].func(listener,
1524 argc - 1, argv + 1);
1533 if ((strcmp(argv[0], "help") == 0) ||
1534 (strcmp(argv[0], "?") == 0)) {
1536 for (i = 0; table[i].command != NULL; i++) {
1537 if (table[i].help) {
1538 cprintf(listener, "%s\n",
1541 cprintf(listener, "%s <command> - do sub-command of %s\n",
1542 table[i].command, table[i].command);
1548 cprintf(listener, "ERROR: Unknown command \"%s\"\r\n",
1553 cprintf(listener, "radmin> ");
1555 if (co->next <= co->offset) {
1558 memmove(co->buffer, co->buffer + co->next,
1559 co->offset - co->next);
1560 co->offset -= co->next;
1567 static int command_domain_accept(rad_listen_t *listener,
1568 UNUSED RAD_REQUEST_FUNP *pfun,
1569 UNUSED REQUEST **prequest)
1575 struct sockaddr_storage src;
1576 fr_command_socket_t *sock = listener->data;
1578 salen = sizeof(src);
1580 DEBUG2(" ... new connection request on command socket.");
1582 newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
1585 * Non-blocking sockets must handle this.
1587 if (errno == EWOULDBLOCK) {
1591 DEBUG2(" ... failed to accept connection.");
1596 * Perform user authentication.
1598 if (sock->uid_name || sock->gid_name) {
1602 if (getpeereid(listener->fd, &uid, &gid) < 0) {
1603 radlog(L_ERR, "Failed getting peer credentials for %s: %s",
1604 sock->path, strerror(errno));
1609 if (sock->uid_name && (sock->uid != uid)) {
1610 radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
1611 sock->path, (long int) uid);
1616 if (sock->gid_name && (sock->gid != gid)) {
1617 radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
1618 sock->path, (long int) gid);
1625 * Write 32-bit magic number && version information.
1627 magic = htonl(0xf7eead15);
1628 if (write(newfd, &magic, 4) < 0) {
1629 radlog(L_ERR, "Failed writing initial data to socket: %s",
1634 magic = htonl(1); /* protocol version */
1635 if (write(newfd, &magic, 4) < 0) {
1636 radlog(L_ERR, "Failed writing initial data to socket: %s",
1644 * Add the new listener.
1646 this = listen_alloc(listener->type);
1647 if (!this) return -1;
1650 * Copy everything, including the pointer to the socket
1654 memcpy(this, listener, sizeof(*this));
1655 this->status = RAD_LISTEN_STATUS_INIT;
1657 this->data = sock; /* fix it back */
1660 sock->user[0] = '\0';
1661 sock->path = ((fr_command_socket_t *) listener->data)->path;
1662 sock->mode = ((fr_command_socket_t *) listener->data)->mode;
1665 this->recv = command_domain_recv;
1668 * Tell the event loop that we have a new FD
1677 * Send an authentication response packet
1679 static int command_domain_send(UNUSED rad_listen_t *listener,
1680 UNUSED REQUEST *request)
1686 static int command_socket_encode(UNUSED rad_listen_t *listener,
1687 UNUSED REQUEST *request)
1693 static int command_socket_decode(UNUSED rad_listen_t *listener,
1694 UNUSED REQUEST *request)
1699 #endif /* WITH_COMMAND_SOCKET */