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>
33 #ifdef HAVE_SYS_STAT_H
45 typedef struct fr_command_table_t fr_command_table_t;
47 typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
52 struct fr_command_table_t {
54 int mode; /* read/write */
56 fr_command_func_t func;
57 fr_command_table_t *table;
60 #define COMMAND_BUFFER_SIZE (1024)
62 typedef struct fr_command_socket_t {
73 char buffer[COMMAND_BUFFER_SIZE];
74 } fr_command_socket_t;
76 static const CONF_PARSER command_config[] = {
77 { "socket", PW_TYPE_STRING_PTR,
78 offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
79 { "uid", PW_TYPE_STRING_PTR,
80 offsetof(fr_command_socket_t, uid_name), NULL, NULL},
81 { "gid", PW_TYPE_STRING_PTR,
82 offsetof(fr_command_socket_t, gid_name), NULL, NULL},
83 { "mode", PW_TYPE_STRING_PTR,
84 offsetof(fr_command_socket_t, mode_name), NULL, NULL},
86 { NULL, -1, 0, NULL, NULL } /* end the list */
89 static FR_NAME_NUMBER mode_names[] = {
91 { "read-only", FR_READ },
92 { "read-write", FR_READ | FR_WRITE },
93 { "rw", FR_READ | FR_WRITE },
97 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
99 __attribute__ ((format (printf, 2, 3)))
103 #ifndef HAVE_GETPEEREID
104 static int getpeereid(int s, uid_t *euid, gid_t *egid)
110 socklen_t cl = sizeof(cr);
112 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
119 #endif /* SO_PEERCRED */
121 #endif /* HAVE_GETPEEREID */
124 static int fr_server_domain_socket(const char *path)
129 struct sockaddr_un salocal;
133 if (len >= sizeof(salocal.sun_path)) {
134 radlog(L_ERR, "Path too long in socket filename.");
138 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
139 radlog(L_ERR, "Failed creating socket: %s",
144 memset(&salocal, 0, sizeof(salocal));
145 salocal.sun_family = AF_UNIX;
146 memcpy(salocal.sun_path, path, len); /* not zero terminated */
148 socklen = sizeof(salocal.sun_family) + len;
153 if (stat(path, &buf) < 0) {
154 if (errno != ENOENT) {
155 radlog(L_ERR, "Failed to stat %s: %s",
156 path, strerror(errno));
161 * FIXME: Check the enclosing directory?
163 } else { /* it exists */
164 if (!S_ISREG(buf.st_mode)
166 && !S_ISSOCK(buf.st_mode)
169 radlog(L_ERR, "Cannot turn %s into socket", path);
174 * Refuse to open sockets not owned by us.
176 if (buf.st_uid != geteuid()) {
177 radlog(L_ERR, "We do not own %s", path);
181 if (unlink(path) < 0) {
182 radlog(L_ERR, "Failed to delete %s: %s",
183 path, strerror(errno));
188 if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
189 radlog(L_ERR, "Failed binding to %s: %s",
190 path, strerror(errno));
196 * FIXME: There's a race condition here. But Linux
197 * doesn't seem to permit fchmod on domain sockets.
199 if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
200 radlog(L_ERR, "Failed setting permissions on %s: %s",
201 path, strerror(errno));
206 if (listen(sockfd, 8) < 0) {
207 radlog(L_ERR, "Failed listening to %s: %s",
208 path, strerror(errno));
217 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
218 radlog(L_ERR, "Failure getting socket flags: %s",
225 if( fcntl(sockfd, F_SETFL, flags) < 0) {
226 radlog(L_ERR, "Failure setting socket flags: %s",
238 static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...)
245 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
248 if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0;
250 len = write(listener->fd, buffer, len);
252 listener->status = RAD_LISTEN_STATUS_CLOSED;
253 event_new_fd(listener);
257 * FIXME: Keep writing until done?
262 static int command_hup(rad_listen_t *listener, int argc, char *argv[])
265 module_instance_t *mi;
268 radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
272 cs = cf_section_find("modules");
275 mi = find_module_instance(cs, argv[0], 0);
277 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
281 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
282 cprintf(listener, "ERROR: Module %s cannot be hup'd\n",
287 if (!module_hup_module(mi->cs, mi, time(NULL))) {
288 cprintf(listener, "ERROR: Failed to reload module\n");
292 return 1; /* success */
295 static int command_terminate(UNUSED rad_listen_t *listener,
296 UNUSED int argc, UNUSED char *argv[])
298 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
300 return 1; /* success */
303 extern time_t fr_start_time;
305 static int command_uptime(rad_listen_t *listener,
306 UNUSED int argc, UNUSED char *argv[])
310 CTIME_R(&fr_start_time, buffer, sizeof(buffer));
311 cprintf(listener, "Up since %s", buffer); /* no \r\n */
313 return 1; /* success */
316 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";
319 * FIXME: Recurse && indent?
321 static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
327 const char *name1 = cf_section_name1(cs);
328 const char *name2 = cf_section_name2(cs);
329 const CONF_PARSER *variables = cf_section_parse_table(cs);
333 cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
335 cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
343 if (variables) for (i = 0; variables[i].name != NULL; i++) {
345 * No base struct offset, data must be the pointer.
346 * If data doesn't exist, ignore the entry, there
347 * must be something wrong.
350 if (!variables[i].data) {
354 data = variables[i].data;;
356 } else if (variables[i].data) {
357 data = variables[i].data;;
360 data = (((char *)base) + variables[i].offset);
363 switch (variables[i].type) {
365 cprintf(listener, "%.*s%s = ?\n", indent, tabs,
369 case PW_TYPE_INTEGER:
370 cprintf(listener, "%.*s%s = %u\n", indent, tabs,
371 variables[i].name, *(int *) data);
375 inet_ntop(AF_INET, data, buffer, sizeof(buffer));
378 case PW_TYPE_IPV6ADDR:
379 inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
382 case PW_TYPE_BOOLEAN:
383 cprintf(listener, "%.*s%s = %s\n", indent, tabs,
385 ((*(int *) data) == 0) ? "no" : "yes");
388 case PW_TYPE_STRING_PTR:
389 case PW_TYPE_FILENAME:
391 * FIXME: Escape things in the string!
393 if (*(char **) data) {
394 cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
395 variables[i].name, *(char **) data);
397 cprintf(listener, "%.*s%s = \n", indent, tabs,
407 cprintf(listener, "%.*s}\n", indent, tabs);
410 static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
413 module_instance_t *mi;
416 cprintf(listener, "ERROR: No module name was given\n");
420 cs = cf_section_find("modules");
423 mi = find_module_instance(cs, argv[0], 0);
425 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
429 cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
431 return 1; /* success */
434 static const char *method_names[RLM_COMPONENT_COUNT] = {
446 static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
450 const module_instance_t *mi;
454 cprintf(listener, "ERROR: No module name was given\n");
458 cs = cf_section_find("modules");
461 mi = find_module_instance(cs, argv[0], 0);
463 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
467 mod = mi->entry->module;
469 for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
470 if (mod->methods[i]) cprintf(listener, "\t%s\n", method_names[i]);
473 return 1; /* success */
477 static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
480 const module_instance_t *mi;
484 cprintf(listener, "ERROR: No module name was given\n");
488 cs = cf_section_find("modules");
491 mi = find_module_instance(cs, argv[0], 0);
493 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
497 mod = mi->entry->module;
499 if ((mod->type & RLM_TYPE_THREAD_SAFE) != 0)
500 cprintf(listener, "\tthread-safe\n");
503 if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
504 cprintf(listener, "\twill-check-config\n");
507 if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
508 cprintf(listener, "\treload-on-hup\n");
510 return 1; /* success */
515 * Show all loaded modules
517 static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
519 CONF_SECTION *cs, *subcs;
521 cs = cf_section_find("modules");
525 while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
526 const char *name1 = cf_section_name1(subcs);
527 const char *name2 = cf_section_name2(subcs);
529 module_instance_t *mi;
532 mi = find_module_instance(cs, name2, 0);
535 cprintf(listener, "\t%s (%s)\n", name2, name1);
537 mi = find_module_instance(cs, name1, 0);
540 cprintf(listener, "\t%s\n", name1);
544 return 1; /* success */
547 static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
550 FILE *fp = fdopen(dup(listener->fd), "a");
553 cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
558 cprintf(listener, "ERROR: <reference> is required\n");
562 ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
564 cprintf(listener, "ERROR: No such item <reference>\n");
568 if (cf_item_is_section(ci)) {
569 cf_section2xml(fp, cf_itemtosection(ci));
571 } else if (cf_item_is_pair(ci)) {
572 cf_pair2xml(fp, cf_itemtopair(ci));
575 cprintf(listener, "ERROR: No such item <reference>\n");
582 return 1; /* success */
585 static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
590 cprintf(listener, "ERROR: Must specify <number>\n");
594 number = atoi(argv[0]);
595 if ((number < 0) || (number > 4)) {
596 cprintf(listener, "ERROR: <number> must be between 0 and 4\n");
600 fr_debug_flag = debug_flag = number;
605 extern char *debug_log_file;
606 static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
609 cprintf(listener, "ERROR: Must specify <filename>\n");
613 if (debug_flag && mainconfig.radlog_dest == RADLOG_STDOUT) {
614 cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
618 if (debug_log_file) {
619 free(debug_log_file);
620 debug_log_file = NULL;
622 debug_log_file = strdup(argv[0]);
627 extern char *debug_condition;
628 static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
631 * Delete old condition.
633 * This is thread-safe because the condition is evaluated
634 * in the main server thread, as is this code.
636 free(debug_condition);
637 debug_condition = NULL;
646 debug_condition = strdup(argv[0]);
651 static int command_show_debug_condition(rad_listen_t *listener,
652 UNUSED int argc, UNUSED char *argv[])
654 if (!debug_condition) return 0;
656 cprintf(listener, "%s\n", debug_condition);
661 static int command_show_debug_file(rad_listen_t *listener,
662 UNUSED int argc, UNUSED char *argv[])
664 if (!debug_log_file) return 0;
666 cprintf(listener, "%s\n", debug_log_file);
671 static int command_show_debug_level(rad_listen_t *listener,
672 UNUSED int argc, UNUSED char *argv[])
674 cprintf(listener, "%d\n", debug_flag);
679 static fr_command_table_t command_table_debug[] = {
680 { "condition", FR_WRITE,
681 "debug condition <condition> - Enable debugging for requests matching <condition>",
682 command_debug_condition, NULL },
685 "debug level <number> - Set debug level to <number>. Higher is more debugging.",
686 command_debug_level, NULL },
689 "debug file <filename> - Send all debuggin output to <filename>",
690 command_debug_file, NULL },
692 { NULL, 0, NULL, NULL, NULL }
695 static fr_command_table_t command_table_show_debug[] = {
696 { "condition", FR_READ,
697 "show debug condition - Shows current debugging condition.",
698 command_show_debug_condition, NULL },
701 "show debug level - Shows current debugging level.",
702 command_show_debug_level, NULL },
705 "show debug file - Shows current debugging file.",
706 command_show_debug_file, NULL },
708 { NULL, 0, NULL, NULL, NULL }
711 static fr_command_table_t command_table_show_module[] = {
713 "show module config <module> - show configuration for <module>",
714 command_show_module_config, NULL },
716 "show module flags <module> - show other module properties",
717 command_show_module_flags, NULL },
719 "shows list of loaded modules",
720 command_show_modules, NULL },
721 { "methods", FR_READ,
722 "show module methods <module> - show sections where <module> may be used",
723 command_show_module_methods, NULL },
725 { NULL, 0, NULL, NULL, NULL }
729 static fr_command_table_t command_table_show[] = {
731 "show config <module> - show configuration for module",
732 command_show_module_config, NULL },
734 "show debug <command> - show debug properties",
735 NULL, command_table_show_debug },
737 "show module <command> - do sub-command of module",
738 NULL, command_table_show_module },
739 { "modules", FR_READ,
740 "show modules - shows list of loaded modules",
741 command_show_modules, NULL },
743 "show uptime - shows time at which server started",
744 command_uptime, NULL },
746 "show xml <reference> - Prints out configuration as XML",
747 command_show_xml, NULL },
748 { NULL, 0, NULL, NULL, NULL }
752 static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
757 module_instance_t *mi;
758 const CONF_PARSER *variables;
762 cprintf(listener, "ERROR: No module name or variable was given\n");
766 cs = cf_section_find("modules");
769 mi = find_module_instance(cs, argv[0], 0);
771 cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
775 if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
776 cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n");
780 variables = cf_section_parse_table(mi->cs);
782 cprintf(listener, "ERROR: Cannot find configuration for module\n");
787 for (i = 0; variables[i].name != NULL; i++) {
789 * FIXME: Recurse into sub-types somehow...
791 if (variables[i].type == PW_TYPE_SUBSECTION) continue;
793 if (strcmp(variables[i].name, argv[1]) == 0) {
800 cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]);
804 i = rcode; /* just to be safe */
807 * It's not part of the dynamic configuration. The module
808 * needs to re-parse && validate things.
810 if (variables[i].data) {
811 cprintf(listener, "ERROR: Variable cannot be dynamically updated\n");
815 data = ((char *) mi->insthandle) + variables[i].offset;
817 cp = cf_pair_find(mi->cs, argv[1]);
821 * Replace the OLD value in the configuration file with
824 * FIXME: Parse argv[2] depending on it's data type!
825 * If it's a string, look for leading single/double quotes,
826 * end then call tokenize functions???
828 cf_pair_replace(mi->cs, cp, argv[2]);
830 rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
833 cprintf(listener, "ERROR: Failed to parse value\n");
837 return 1; /* success */
841 static fr_command_table_t command_table_set_module[] = {
842 { "config", FR_WRITE,
843 "set module config <module> variable value - set configuration for <module>",
844 command_set_module_config, NULL },
846 { NULL, 0, NULL, NULL, NULL }
850 static fr_command_table_t command_table_set[] = {
851 { "module", FR_WRITE, NULL, NULL, command_table_set_module },
853 { NULL, 0, NULL, NULL, NULL }
857 static fr_command_table_t command_table[] = {
859 "debug <command> - debugging commands",
860 NULL, command_table_debug },
862 "hup [module] - sends a HUP signal to the server, or optionally to one module",
864 { "reconnect", FR_READ,
865 "reconnect - reconnect to a running server",
866 NULL, NULL }, /* just here for "help" */
867 { "terminate", FR_WRITE,
868 "terminate - terminates the server, and causes it to exit",
869 command_terminate, NULL },
870 { "show", FR_READ, NULL, NULL, command_table_show },
871 { "set", FR_WRITE, NULL, NULL, command_table_set },
873 { NULL, 0, NULL, NULL, NULL }
878 * Parse the unix domain sockets.
880 * FIXME: TCP + SSL, after RadSec is in.
882 static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
884 fr_command_socket_t *sock;
888 if (cf_section_parse(cs, sock, command_config) < 0) {
892 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
893 if (sock->uid_name) {
896 pw = getpwnam(sock->uid_name);
898 radlog(L_ERR, "Failed getting uid for %s: %s",
899 sock->uid_name, strerror(errno));
903 sock->uid = pw->pw_uid;
906 if (sock->gid_name) {
909 gr = getgrnam(sock->gid_name);
911 radlog(L_ERR, "Failed getting gid for %s: %s",
912 sock->gid_name, strerror(errno));
915 sock->gid = gr->gr_gid;
918 #else /* can't get uid or gid of connecting user */
920 if (sock->uid_name || sock->gid_name) {
921 radlog(L_ERR, "System does not support uid or gid authentication for sockets");
927 if (!sock->mode_name) {
928 sock->mode = FR_READ;
930 sock->mode = fr_str2int(mode_names, sock->mode_name, 0);
932 radlog(L_ERR, "Invalid mode name \"%s\"",
939 * FIXME: check for absolute pathnames?
940 * check for uid/gid on the other end...
943 this->fd = fr_server_domain_socket(sock->path);
951 static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
953 fr_command_socket_t *sock = this->data;
955 snprintf(buffer, bufsize, "command file %s", sock->path);
961 * String split routine. Splits an input string IN PLACE
962 * into pieces, based on spaces.
964 static int str2argv(char *str, char **argv, int max_argc)
971 if (argc >= max_argc) return argc;
974 * Chop out comments early.
981 while ((*str == ' ') ||
984 (*str == '\n')) *(str++) = '\0';
986 if (!*str) return argc;
988 if ((*str == '\'') || (*str == '"')) {
992 token = gettoken((const char **) &p, buffer,
994 if ((token != T_SINGLE_QUOTED_STRING) &&
995 (token != T_DOUBLE_QUOTED_STRING)) {
999 len = strlen(buffer);
1000 if (len >= (size_t) (p - str)) {
1004 memcpy(str, buffer, len + 1);
1017 (*str != '\n')) str++;
1023 #define MAX_ARGV (16)
1026 * Check if an incoming request is "ok"
1028 * It takes packets, not requests. It sees if the packet looks
1029 * OK. If so, it does a number of sanity checks on it.
1031 static int command_domain_recv(rad_listen_t *listener,
1032 UNUSED RAD_REQUEST_FUNP *pfun,
1033 UNUSED REQUEST **prequest)
1038 char *my_argv[MAX_ARGV], **argv;
1039 fr_command_table_t *table;
1040 fr_command_socket_t *co = listener->data;
1049 len = recv(listener->fd, co->buffer + co->offset,
1050 sizeof(co->buffer) - co->offset - 1, 0);
1051 if (len == 0) goto close_socket; /* clean close */
1054 if ((errno == EAGAIN) || (errno == EINTR)) {
1063 if ((co->offset == 0) && (co->buffer[0] == 0x04)) {
1065 listener->status = RAD_LISTEN_STATUS_CLOSED;
1066 event_new_fd(listener);
1071 * See if there are multiple lines in the buffer.
1073 p = co->buffer + co->offset;
1076 for (c = 0; c < len; c++) {
1077 if ((*p == '\r') || (*p == '\n')) {
1082 * FIXME: do real buffering...
1083 * handling of CTRL-C, etc.
1088 * \r \n followed by ASCII...
1099 * Saw CR/LF. Set next element, and exit.
1102 co->next = p - co->buffer;
1106 if (co->offset >= (ssize_t) (sizeof(co->buffer) - 1)) {
1107 radlog(L_ERR, "Line too long!");
1114 argc = str2argv(co->buffer, my_argv, MAX_ARGV);
1115 if (argc == 0) goto do_next; /* empty strings are OK */
1118 cprintf(listener, "ERROR: Failed parsing command.\n");
1124 for (len = 0; len <= co->offset; len++) {
1125 if (co->buffer[len] < 0x20) {
1126 co->buffer[len] = '\0';
1132 * Hard-code exit && quit.
1134 if ((strcmp(argv[0], "exit") == 0) ||
1135 (strcmp(argv[0], "quit") == 0)) goto close_socket;
1139 if (strcmp(argv[0], "login") != 0) {
1140 cprintf(listener, "ERROR: Login required\n");
1145 cprintf(listener, "ERROR: login <user> <password>\n");
1150 * FIXME: Generate && process fake RADIUS request.
1152 if ((strcmp(argv[1], "root") == 0) &&
1153 (strcmp(argv[2], "password") == 0)) {
1154 strlcpy(co->user, argv[1], sizeof(co->user));
1158 cprintf(listener, "ERROR: Login incorrect\n");
1163 table = command_table;
1166 for (i = 0; table[i].command != NULL; i++) {
1167 if (strcmp(table[i].command, argv[0]) == 0) {
1169 * Check permissions.
1171 if (((co->mode & FR_WRITE) == 0) &&
1172 ((table[i].mode & FR_WRITE) != 0)) {
1173 cprintf(listener, "ERROR: You do not have write permission.\n");
1177 if (table[i].table) {
1179 * This is the last argument, but
1180 * there's a sub-table. Print help.
1184 table = table[i].table;
1190 table = table[i].table;
1194 if (!table[i].func) {
1195 cprintf(listener, "ERROR: Invalid command\n");
1200 rcode = table[i].func(listener,
1201 argc - 1, argv + 1);
1210 if ((strcmp(argv[0], "help") == 0) ||
1211 (strcmp(argv[0], "?") == 0)) {
1213 for (i = 0; table[i].command != NULL; i++) {
1214 if (table[i].help) {
1215 cprintf(listener, "%s\n",
1218 cprintf(listener, "%s <command> - do sub-command of %s\n",
1219 table[i].command, table[i].command);
1225 cprintf(listener, "ERROR: Unknown command \"%s\"\r\n",
1230 cprintf(listener, "radmin> ");
1232 if (co->next <= co->offset) {
1235 memmove(co->buffer, co->buffer + co->next,
1236 co->offset - co->next);
1237 co->offset -= co->next;
1244 static int command_domain_accept(rad_listen_t *listener,
1245 UNUSED RAD_REQUEST_FUNP *pfun,
1246 UNUSED REQUEST **prequest)
1252 struct sockaddr_storage src;
1253 fr_command_socket_t *sock = listener->data;
1255 salen = sizeof(src);
1257 DEBUG2(" ... new connection request on command socket.");
1259 newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
1262 * Non-blocking sockets must handle this.
1264 if (errno == EWOULDBLOCK) {
1268 DEBUG2(" ... failed to accept connection.");
1273 * Perform user authentication.
1275 if (sock->uid_name || sock->gid_name) {
1279 if (getpeereid(listener->fd, &uid, &gid) < 0) {
1280 radlog(L_ERR, "Failed getting peer credentials for %s: %s",
1281 sock->path, strerror(errno));
1286 if (sock->uid_name && (sock->uid != uid)) {
1287 radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
1288 sock->path, (long int) uid);
1293 if (sock->gid_name && (sock->gid != gid)) {
1294 radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
1295 sock->path, (long int) gid);
1302 * Write 32-bit magic number && version information.
1304 magic = htonl(0xf7eead15);
1305 if (write(newfd, &magic, 4) < 0) {
1306 radlog(L_ERR, "Failed writing initial data to socket: %s",
1311 magic = htonl(1); /* protocol version */
1312 if (write(newfd, &magic, 4) < 0) {
1313 radlog(L_ERR, "Failed writing initial data to socket: %s",
1321 * Add the new listener.
1323 this = listen_alloc(listener->type);
1324 if (!this) return -1;
1327 * Copy everything, including the pointer to the socket
1331 memcpy(this, listener, sizeof(*this));
1332 this->status = RAD_LISTEN_STATUS_INIT;
1334 this->data = sock; /* fix it back */
1337 sock->user[0] = '\0';
1338 sock->path = ((fr_command_socket_t *) listener->data)->path;
1339 sock->mode = ((fr_command_socket_t *) listener->data)->mode;
1342 this->recv = command_domain_recv;
1345 * Tell the event loop that we have a new FD
1354 * Send an authentication response packet
1356 static int command_domain_send(UNUSED rad_listen_t *listener,
1357 UNUSED REQUEST *request)
1363 static int command_socket_encode(UNUSED rad_listen_t *listener,
1364 UNUSED REQUEST *request)
1370 static int command_socket_decode(UNUSED rad_listen_t *listener,
1371 UNUSED REQUEST *request)
1376 #endif /* WITH_COMMAND_SOCKET */