typedef struct fr_command_socket_t {
char *path;
+ char *copy; /* <sigh> */
uid_t uid;
gid_t gid;
int mode;
return sockfd;
}
+
static void command_close_socket(rad_listen_t *this)
{
this->status = RAD_LISTEN_STATUS_CLOSED;
* will be calling us any more.
*/
event_new_fd(this);
-
- listen_free(&this);
}
data = variables[i].data;;
} else {
- data = (((char *)base) + variables[i].offset);
+ data = (((const char *)base) + variables[i].offset);
}
switch (variables[i].type) {
case PW_TYPE_INTEGER:
cprintf(listener, "%.*s%s = %u\n", indent, tabs,
- variables[i].name, *(int *) data);
+ variables[i].name, *(const int *) data);
break;
case PW_TYPE_IPADDR:
case PW_TYPE_BOOLEAN:
cprintf(listener, "%.*s%s = %s\n", indent, tabs,
variables[i].name,
- ((*(int *) data) == 0) ? "no" : "yes");
+ ((*(const int *) data) == 0) ? "no" : "yes");
break;
case PW_TYPE_STRING_PTR:
/*
* FIXME: Escape things in the string!
*/
- if (*(char **) data) {
+ if (*(const char * const *) data) {
cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
- variables[i].name, *(char **) data);
+ variables[i].name, *(const char * const *) data);
} else {
cprintf(listener, "%.*s%s = \n", indent, tabs,
variables[i].name);
{
int i;
home_server *home;
- const char *type, *state;
+ const char *type, *state, *proto;
char buffer[256];
} else continue;
+ if (home->proto == IPPROTO_UDP) {
+ proto = "udp";
+ }
+#ifdef WITH_TCP
+ else if (home->proto == IPPROTO_TCP) {
+ proto = "tcp";
+ }
+#endif
+ else proto = "??";
+
if (home->state == HOME_STATE_ALIVE) {
state = "alive";
} else continue;
- cprintf(listener, "%s\t%d\t%s\t%s\t%d\n",
+ cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\n",
ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
- home->port, type, state,
+ home->port, proto, type, state,
home->currently_outstanding);
}
{
RADCLIENT *client;
fr_ipaddr_t ipaddr;
+ int proto = IPPROTO_UDP;
if (argc < 1) {
cprintf(listener, "ERROR: Must specify <ipaddr>\n");
return NULL;
}
- client = client_find(NULL, &ipaddr);
+#ifdef WITH_TCP
+ if (argc >= 2) {
+ if (strcmp(argv[1], "tcp") == 0) {
+ proto = IPPROTO_TCP;
+
+ } else if (strcmp(argv[1], "udp") == 0) {
+ proto = IPPROTO_UDP;
+
+ } else {
+ cprintf(listener, "ERROR: Unknown protocol %s. Please use \"udp\" or \"tcp\"\n",
+ argv[1]);
+ return NULL;
+ }
+ }
+#endif
+
+ client = client_find(NULL, &ipaddr, proto);
if (!client) {
cprintf(listener, "ERROR: No such client\n");
return NULL;
}
#ifdef WITH_PROXY
-static home_server *get_home_server(rad_listen_t *listener, int argc, char *argv[])
+static home_server *get_home_server(rad_listen_t *listener, int argc,
+ char *argv[], int *last)
{
home_server *home;
int port;
+ int proto = IPPROTO_UDP;
fr_ipaddr_t ipaddr;
if (argc < 2) {
- cprintf(listener, "ERROR: Must specify <ipaddr> <port>\n");
+ cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto]\n");
return NULL;
}
port = atoi(argv[1]);
- home = home_server_find(&ipaddr, port);
+ if (last) *last = 2;
+ if (argc > 2) {
+ if (strcmp(argv[2], "udp") == 0) {
+ proto = IPPROTO_UDP;
+ if (last) *last = 3;
+ }
+#ifdef WITH_TCP
+ if (strcmp(argv[2], "tcp") == 0) {
+ proto = IPPROTO_TCP;
+ if (last) *last = 3;
+ }
+#endif
+ }
+
+ home = home_server_find(&ipaddr, port, proto);
if (!home) {
cprintf(listener, "ERROR: No such home server\n");
return NULL;
home_server *home;
FILE *fp;
- home = get_home_server(listener, argc, argv);
+ home = get_home_server(listener, argc, argv, NULL);
if (!home) {
return 0;
}
static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
{
+ int last;
home_server *home;
if (argc < 3) {
- cprintf(listener, "ERROR: Must specify <ipaddr> <port> <state>\n");
+ cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto] <state>\n");
return 0;
}
- home = get_home_server(listener, argc, argv);
+ home = get_home_server(listener, argc, argv, &last);
if (!home) {
return 0;
}
- if (strcmp(argv[2], "alive") == 0) {
+ if (strcmp(argv[last], "alive") == 0) {
revive_home_server(home);
- } else if (strcmp(argv[2], "dead") == 0) {
+ } else if (strcmp(argv[last], "dead") == 0) {
struct timeval now;
gettimeofday(&now, NULL); /* we do this WAY too ofetn */
mark_home_server_dead(home, &now);
} else {
- cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[2]);
+ cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[last]);
return 0;
}
{
home_server *home;
- home = get_home_server(listener, argc, argv);
+ home = get_home_server(listener, argc, argv, NULL);
if (!home) {
return 0;
}
static fr_command_table_t command_table_show_client[] = {
{ "config", FR_READ,
- "show client config <ipaddr> - show configuration for given client",
+ "show client config <ipaddr> "
+#ifdef WITH_TCP
+ "[proto] "
+#endif
+ "- show configuration for given client",
command_show_client_config, NULL },
{ "list", FR_READ,
"show client list - shows list of global clients",
#ifdef WITH_PROXY
static fr_command_table_t command_table_show_home[] = {
{ "config", FR_READ,
- "show home_server config <ipaddr> <port> - show configuration for given home server",
+ "show home_server config <ipaddr> <port> [proto] - show configuration for given home server",
command_show_home_server_config, NULL },
{ "list", FR_READ,
"show home_server list - shows list of home servers",
command_show_home_servers, NULL },
{ "state", FR_READ,
- "show home_server state <ipaddr> <port> - shows state of given home server",
+ "show home_server state <ipaddr> <port> [proto] - shows state of given home server",
command_show_home_server_state, NULL },
{ NULL, 0, NULL, NULL, NULL }
return 1; /* success */
}
+static int command_set_module_status(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+
+ if (argc < 2) {
+ cprintf(listener, "ERROR: No module name or status was given\n");
+ return 0;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return 0;
+
+ mi = find_module_instance(cs, argv[0], 0);
+ if (!mi) {
+ cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
+ return 0;
+ }
+
+
+ if (strcmp(argv[1], "alive") == 0) {
+ mi->dead = FALSE;
+
+ } else if (strcmp(argv[1], "dead") == 0) {
+ mi->dead = TRUE;
+
+ } else {
+ cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[2]);
+ return 0;
+ }
+
+ return 1; /* success */
+}
+
static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
int auth)
{
- cprintf(listener, "\trequests\t%d\n", stats->total_requests);
- cprintf(listener, "\tresponses\t%d\n", stats->total_responses);
+ cprintf(listener, "\trequests\t%u\n", stats->total_requests);
+ cprintf(listener, "\tresponses\t%u\n", stats->total_responses);
if (auth) {
- cprintf(listener, "\taccepts\t\t%d\n",
+ cprintf(listener, "\taccepts\t\t%u\n",
stats->total_access_accepts);
- cprintf(listener, "\trejects\t\t%d\n",
+ cprintf(listener, "\trejects\t\t%u\n",
stats->total_access_rejects);
- cprintf(listener, "\tchallenges\t%d\n",
+ cprintf(listener, "\tchallenges\t%u\n",
stats->total_access_challenges);
}
- cprintf(listener, "\tdup\t\t%d\n", stats->total_dup_requests);
- cprintf(listener, "\tinvalid\t\t%d\n", stats->total_invalid_requests);
- cprintf(listener, "\tmalformed\t%d\n", stats->total_malformed_requests);
- cprintf(listener, "\tbad_signature\t%d\n", stats->total_bad_authenticators);
- cprintf(listener, "\tdropped\t\t%d\n", stats->total_packets_dropped);
- cprintf(listener, "\tunknown_types\t%d\n", stats->total_unknown_types);
+ cprintf(listener, "\tdup\t\t%u\n", stats->total_dup_requests);
+ cprintf(listener, "\tinvalid\t\t%u\n", stats->total_invalid_requests);
+ cprintf(listener, "\tmalformed\t%u\n", stats->total_malformed_requests);
+ cprintf(listener, "\tbad_signature\t%u\n", stats->total_bad_authenticators);
+ cprintf(listener, "\tdropped\t\t%u\n", stats->total_packets_dropped);
+ cprintf(listener, "\tunknown_types\t%u\n", stats->total_unknown_types);
return 1;
}
+#ifdef WITH_DETAIL
+static FR_NAME_NUMBER state_names[] = {
+ { "unopened", STATE_UNOPENED },
+ { "unlocked", STATE_UNLOCKED },
+ { "header", STATE_HEADER },
+ { "reading", STATE_READING },
+ { "queued", STATE_QUEUED },
+ { "running", STATE_RUNNING },
+ { "no-reply", STATE_NO_REPLY },
+ { "replied", STATE_REPLIED },
+
+ { NULL, 0 }
+};
+
+static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
+{
+ rad_listen_t *this;
+ listen_detail_t *data;
+ struct stat buf;
+
+ if (argc == 0) {
+ cprintf(listener, "ERROR: Must specify <filename>\n");
+ return 0;
+ }
+
+ data = NULL;
+ for (this = mainconfig.listen; this != NULL; this = this->next) {
+ if (this->type != RAD_LISTEN_DETAIL) continue;
+
+ data = this->data;
+ if (strcmp(argv[1], data->filename) != 0) continue;
+
+ break;
+ }
+
+ cprintf(listener, "\tstate\t%s\n",
+ fr_int2str(state_names, data->state, "?"));
+
+ if ((data->state == STATE_UNOPENED) ||
+ (data->state == STATE_UNLOCKED)) {
+ return 1;
+ }
+
+ /*
+ * Race conditions: file might not exist.
+ */
+ if (stat(data->filename_work, &buf) < 0) {
+ cprintf(listener, "packets\t0\n");
+ cprintf(listener, "tries\t0\n");
+ cprintf(listener, "offset\t0\n");
+ cprintf(listener, "size\t0\n");
+ return 1;
+ }
+
+ cprintf(listener, "packets\t%d\n", data->packets);
+ cprintf(listener, "tries\t%d\n", data->tries);
+ cprintf(listener, "offset\t%u\n", (unsigned int) data->offset);
+ cprintf(listener, "size\t%u\n", (unsigned int) buf.st_size);
+
+ return 1;
+}
+#endif
+
#ifdef WITH_PROXY
static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
{
return 0;
}
- home = get_home_server(listener, argc, argv);
+ home = get_home_server(listener, argc, argv, NULL);
if (!home) {
return 0;
}
}
+static int command_del_client(rad_listen_t *listener, int argc, char *argv[])
+{
+#ifdef WITH_DYNAMIC_CLIENTS
+ RADCLIENT *client;
+
+ client = get_client(listener, argc - 1, argv + 1);
+ if (!client) return 0;
+
+ if (!client->dynamic) {
+ cprintf(listener, "ERROR: Client %s was not dynamically defined.\n", argv[1]);
+ return 0;
+ }
+
+ /*
+ * DON'T delete it. Instead, mark it as "dead now". The
+ * next time we receive a packet for the client, it will
+ * be deleted.
+ *
+ * If we don't receive a packet from it, the client
+ * structure will stick around for a while. Oh well...
+ */
+ client->lifetime = 1;
+#else
+ cprintf(listener, "ERROR: Dynamic clients are not supported.\n");
+#endif
+
+ return 1;
+}
+
+
+static fr_command_table_t command_table_del_client[] = {
+ { "ipaddr", FR_WRITE,
+ "del client ipaddr <ipaddr> - Delete a dynamically created client",
+ command_del_client, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
+static fr_command_table_t command_table_del[] = {
+ { "client", FR_WRITE,
+ "del client <command> - Delete client configuration commands",
+ NULL, command_table_del_client },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
static fr_command_table_t command_table_add_client[] = {
{ "file", FR_WRITE,
"add client file <filename> - Add new client definition from <filename>",
#ifdef WITH_PROXY
static fr_command_table_t command_table_set_home[] = {
{ "state", FR_WRITE,
- "set home_server state <ipaddr> <port> [alive|dead] - set state for given home server",
+ "set home_server state <ipaddr> <port> [proto] [alive|dead] - set state for given home server",
command_set_home_server_state, NULL },
{ NULL, 0, NULL, NULL, NULL }
"set module config <module> variable value - set configuration for <module>",
command_set_module_config, NULL },
+ { "status", FR_WRITE,
+ "set module status [alive|dead] - set the module to be alive or dead (always return \"fail\")",
+ command_set_module_status, NULL },
+
{ NULL, 0, NULL, NULL, NULL }
};
static fr_command_table_t command_table_stats[] = {
{ "client", FR_READ,
- "stats client [auth/acct] <ipaddr> - show statistics for client",
+ "stats client [auth/acct] <ipaddr> "
+#ifdef WITH_TCP
+ "[proto] "
+#endif
+ "- show statistics for given client, or for all clients (auth or acct)",
command_stats_client, NULL },
#ifdef WITH_PROXY
{ "home_server", FR_READ,
- "stats home_server <ipaddr> <port> - show statistics for home server",
+ "stats home_server [<ipaddr>/auth/acct] <port> - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
command_stats_home_server, NULL },
#endif
+#ifdef WITH_DETAIL
+ { "detail", FR_READ,
+ "stats detail <filename> - show statistics for the given detail file",
+ command_stats_detail, NULL },
+#endif
+
{ NULL, 0, NULL, NULL, NULL }
};
{ "debug", FR_WRITE,
"debug <command> - debugging commands",
NULL, command_table_debug },
+ { "del", FR_WRITE, NULL, NULL, command_table_del },
{ "hup", FR_WRITE,
"hup [module] - sends a HUP signal to the server, or optionally to one module",
command_hup, NULL },
};
+static void command_socket_free(rad_listen_t *this)
+{
+ fr_command_socket_t *sock = this->data;
+
+ unlink(sock->copy);
+ free(sock->copy);
+ sock->copy = NULL;
+}
+
+
/*
* Parse the unix domain sockets.
*
{
fr_command_socket_t *sock;
+ if (check_config) return 0;
+
sock = this->data;
if (cf_section_parse(cs, sock, command_config) < 0) {
return -1;
}
+ sock->copy = NULL;
+ if (sock->path) sock->copy = strdup(sock->path);
+
#if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
if (sock->uid_name) {
struct passwd *pw;
return 0;
}
-static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
+static int command_socket_print(const rad_listen_t *this, char *buffer, size_t bufsize)
{
fr_command_socket_t *sock = this->data;
co->offset++;
} while (1);
+ DEBUG("radmin> %s", co->buffer);
+
argc = str2argv(co->buffer, my_argv, MAX_ARGV);
if (argc == 0) goto do_next; /* empty strings are OK */
*/
if (((co->mode & FR_WRITE) == 0) &&
((table[i].mode & FR_WRITE) != 0)) {
- cprintf(listener, "ERROR: You do not have write permission.\n");
+ cprintf(listener, "ERROR: You do not have write permission. See \"mode = rw\" in the \"listen\" section for this socket.\n");
goto do_next;
}
goto retry;
}
+ if ((argc == 2) && (strcmp(argv[1], "?") == 0)) goto do_help;
+
if (!table[i].func) {
cprintf(listener, "ERROR: Invalid command\n");
goto do_next;
if (!len) {
if ((strcmp(argv[0], "help") == 0) ||
(strcmp(argv[0], "?") == 0)) {
- int recursive = 0;
+ int recursive;
do_help:
if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
recursive = TRUE;
+ } else {
+ recursive = FALSE;
}
print_help(listener, table, recursive);
salen = sizeof(src);
DEBUG2(" ... new connection request on command socket.");
+
+ *pfun = NULL;
+ *prequest = NULL;
newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
if (newfd < 0) {
}
DEBUG2(" ... failed to accept connection.");
- return -1;
+ return 0;
}
/*
radlog(L_ERR, "Failed getting peer credentials for %s: %s",
sock->path, strerror(errno));
close(newfd);
- return -1;
+ return 0;
}
if (sock->uid_name && (sock->uid != uid)) {
radlog(L_ERR, "Unauthorized connection to %s from uid %ld",
sock->path, (long int) uid);
close(newfd);
- return -1;
+ return 0;
}
if (sock->gid_name && (sock->gid != gid)) {
radlog(L_ERR, "Unauthorized connection to %s from gid %ld",
sock->path, (long int) gid);
close(newfd);
- return -1;
+ return 0;
}
}
radlog(L_ERR, "Failed writing initial data to socket: %s",
strerror(errno));
close(newfd);
- return -1;
+ return 0;
}
magic = htonl(1); /* protocol version */
if (write(newfd, &magic, 4) < 0) {
radlog(L_ERR, "Failed writing initial data to socket: %s",
strerror(errno));
close(newfd);
- return -1;
+ return 0;
}
* Add the new listener.
*/
this = listen_alloc(listener->type);
- if (!this) return -1;
+ if (!this) return 0;
/*
* Copy everything, including the pointer to the socket