X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fcommand.c;h=1b6e9c3e2093143ddc3c0ba1c2165a1a7415afe4;hb=d8b47607f33382da1f753b7c7aea81c95d1be8a5;hp=b021ab9efca196e014d3afa29c0d1ae07b5b5c37;hpb=fb3aeffe88a69999dab009d06b9bf9fce6c94524;p=freeradius.git diff --git a/src/main/command.c b/src/main/command.c index b021ab9..1b6e9c3 100644 --- a/src/main/command.c +++ b/src/main/command.c @@ -25,9 +25,14 @@ #include #include -# +#include +#include + #ifdef HAVE_SYS_UN_H #include +#ifndef SUN_LEN +#define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif #endif #ifdef HAVE_SYS_STAT_H @@ -46,8 +51,12 @@ typedef struct fr_command_table_t fr_command_table_t; typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]); +#define FR_READ (1) +#define FR_WRITE (2) + struct fr_command_table_t { const char *command; + int mode; /* read/write */ const char *help; fr_command_func_t func; fr_command_table_t *table; @@ -57,11 +66,28 @@ struct fr_command_table_t { typedef struct fr_command_socket_t { char *path; + char *copy; /* */ uid_t uid; gid_t gid; + int mode; char *uid_name; char *gid_name; + char *mode_name; char user[256]; + + /* + * The next few entries handle fake packets injected by + * the control socket. + */ + fr_ipaddr_t src_ipaddr; /* src_port is always 0 */ + fr_ipaddr_t dst_ipaddr; + int dst_port; + rad_listen_t *inject_listener; + RADCLIENT *inject_client; + + /* + * The next few entries do buffer management. + */ ssize_t offset; ssize_t next; char buffer[COMMAND_BUFFER_SIZE]; @@ -74,10 +100,21 @@ static const CONF_PARSER command_config[] = { offsetof(fr_command_socket_t, uid_name), NULL, NULL}, { "gid", PW_TYPE_STRING_PTR, offsetof(fr_command_socket_t, gid_name), NULL, NULL}, + { "mode", PW_TYPE_STRING_PTR, + offsetof(fr_command_socket_t, mode_name), NULL, NULL}, { NULL, -1, 0, NULL, NULL } /* end the list */ }; +static FR_NAME_NUMBER mode_names[] = { + { "ro", FR_READ }, + { "read-only", FR_READ }, + { "read-write", FR_READ | FR_WRITE }, + { "rw", FR_READ | FR_WRITE }, + { NULL, 0 } +}; + + static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))) @@ -127,9 +164,9 @@ static int fr_server_domain_socket(const char *path) memset(&salocal, 0, sizeof(salocal)); salocal.sun_family = AF_UNIX; - memcpy(salocal.sun_path, path, len); /* not zero terminated */ + memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */ - socklen = sizeof(salocal.sun_family) + len; + socklen = SUN_LEN(&salocal); /* * Check the path. @@ -219,6 +256,18 @@ static int fr_server_domain_socket(const char *path) } +static void command_close_socket(rad_listen_t *this) +{ + this->status = RAD_LISTEN_STATUS_CLOSED; + + /* + * This removes the socket from the event fd, so no one + * will be calling us any more. + */ + event_new_fd(this); +} + + static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...) { ssize_t len; @@ -232,10 +281,7 @@ static ssize_t cprintf(rad_listen_t *listener, const char *fmt, ...) if (listener->status == RAD_LISTEN_STATUS_CLOSED) return 0; len = write(listener->fd, buffer, len); - if (len < 0) { - listener->status = RAD_LISTEN_STATUS_CLOSED; - event_new_fd(listener); - } + if (len <= 0) command_close_socket(listener); /* * FIXME: Keep writing until done? @@ -341,7 +387,7 @@ static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION data = variables[i].data;; } else { - data = (((char *)base) + variables[i].offset); + data = (((const char *)base) + variables[i].offset); } switch (variables[i].type) { @@ -352,7 +398,7 @@ static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION 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: @@ -366,7 +412,7 @@ static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION 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: @@ -374,9 +420,9 @@ static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION /* * 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); @@ -528,6 +574,89 @@ static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED return 1; /* success */ } +#ifdef WITH_PROXY +static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[]) +{ + int i; + home_server *home; + const char *type, *state, *proto; + + char buffer[256]; + + for (i = 0; i < 256; i++) { + home = home_server_bynumber(i); + if (!home) break; + + /* + * Internal "virtual" home server. + */ + if (home->ipaddr.af == AF_UNSPEC) continue; + + if (home->type == HOME_TYPE_AUTH) { + type = "auth"; + + } else if (home->type == HOME_TYPE_ACCT) { + type = "acct"; + + } 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 if (home->state == HOME_STATE_ZOMBIE) { + state = "zombie"; + + } else if (home->state == HOME_STATE_IS_DEAD) { + state = "dead"; + + } else continue; + + cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\n", + ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)), + home->port, proto, type, state, + home->currently_outstanding); + } + + return 0; +} +#endif + +static int command_show_clients(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[]) +{ + int i; + RADCLIENT *client; + char buffer[256]; + + for (i = 0; i < 256; i++) { + client = client_findbynumber(NULL, i); + if (!client) break; + + ip_ntoh(&client->ipaddr, buffer, sizeof(buffer)); + + if (((client->ipaddr.af == AF_INET) && + (client->prefix != 32)) || + ((client->ipaddr.af == AF_INET6) && + (client->prefix != 128))) { + cprintf(listener, "\t%s/%d\n", buffer, client->prefix); + } else { + cprintf(listener, "\t%s\n", buffer); + } + } + + return 0; +} + + static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[]) { CONF_ITEM *ci; @@ -566,6 +695,12 @@ static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char return 1; /* success */ } +static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[]) +{ + cprintf(listener, "%s\n", radiusd_version); + return 1; +} + static int command_debug_level(rad_listen_t *listener, int argc, char *argv[]) { int number; @@ -586,201 +721,1187 @@ static int command_debug_level(rad_listen_t *listener, int argc, char *argv[]) return 0; } -extern char *debug_log_file; +char *debug_log_file = NULL; +static char debug_log_file_buffer[1024]; + static int command_debug_file(rad_listen_t *listener, int argc, char *argv[]) { - if (argc == 0) { - cprintf(listener, "ERROR: Must specify \n"); + if (debug_flag && mainconfig.radlog_dest == RADLOG_STDOUT) { + cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n"); return -1; } - if (debug_log_file) { - free(debug_log_file); - debug_log_file = NULL; + if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) != NULL)) { + cprintf(listener, "ERROR: Cannot direct debug logs to absolute path.\n"); } - debug_log_file = strdup(argv[1]); + + debug_log_file = NULL; + + if (argc == 0) return 0; + + /* + * This looks weird, but it's here to avoid locking + * a mutex for every log message. + */ + memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer)); + + /* + * Debug files always go to the logging directory. + */ + snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer), + "%s/%s", radlog_dir, argv[0]); + + debug_log_file = &debug_log_file_buffer[0]; return 0; } -static fr_command_table_t command_table_debug[] = { - { "level", - "debug level - Set debug level to . Higher is more debugging.", - command_debug_level, NULL }, +extern char *debug_condition; +static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[]) +{ + /* + * Delete old condition. + * + * This is thread-safe because the condition is evaluated + * in the main server thread, as is this code. + */ + free(debug_condition); + debug_condition = NULL; - { "file", - "debug file - Send debug output to ", - command_debug_file, NULL }, + /* + * Disable it. + */ + if (argc == 0) { + return 0; + } - { NULL, NULL, NULL, NULL } -}; + debug_condition = strdup(argv[0]); -static fr_command_table_t command_table_show_module[] = { - { "config", - "show module config - show configuration for ", - command_show_module_config, NULL }, - { "flags", - "show module flags - show other module properties", - command_show_module_flags, NULL }, - { "list", - "shows list of loaded modules", - command_show_modules, NULL }, - { "methods", - "show module methods - show sections where may be used", - command_show_module_methods, NULL }, + return 0; +} - { NULL, NULL, NULL, NULL } -}; +static int command_show_debug_condition(rad_listen_t *listener, + UNUSED int argc, UNUSED char *argv[]) +{ + if (!debug_condition) return 0; + cprintf(listener, "%s\n", debug_condition); + return 0; +} -static fr_command_table_t command_table_show[] = { - { "config", - "show config - show configuration for module", - command_show_module_config, NULL }, - { "module", - "show module - do sub-command of module", - NULL, command_table_show_module }, - { "modules", - "show modules - shows list of loaded modules", - command_show_modules, NULL }, - { "uptime", - "show uptime - shows time at which server started", - command_uptime, NULL }, - { "xml", - "show xml - Prints out configuration as XML", - command_show_xml, NULL }, - { NULL, NULL, NULL, NULL } -}; +static int command_show_debug_file(rad_listen_t *listener, + UNUSED int argc, UNUSED char *argv[]) +{ + if (!debug_log_file) return 0; -static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[]) + cprintf(listener, "%s\n", debug_log_file); + return 0; +} + + +static int command_show_debug_level(rad_listen_t *listener, + UNUSED int argc, UNUSED char *argv[]) { - int i, rcode; - CONF_PAIR *cp; - CONF_SECTION *cs; - module_instance_t *mi; - const CONF_PARSER *variables; - void *data; + cprintf(listener, "%d\n", debug_flag); + return 0; +} - if (argc < 3) { - cprintf(listener, "ERROR: No module name or variable was given\n"); - return 0; + +static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[]) +{ + RADCLIENT *client; + fr_ipaddr_t ipaddr; + int proto = IPPROTO_UDP; + + if (argc < 1) { + cprintf(listener, "ERROR: Must specify \n"); + return NULL; } - cs = cf_section_find("modules"); - if (!cs) return 0; + if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) { + cprintf(listener, "ERROR: Failed parsing IP address; %s\n", + fr_strerror()); + return NULL; + } - mi = find_module_instance(cs, argv[0], 0); - if (!mi) { - cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]); - return 0; +#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 - if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) { - cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n"); + client = client_find(NULL, &ipaddr, proto); + if (!client) { + cprintf(listener, "ERROR: No such client\n"); + return NULL; + } + + return client; +} + + +static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[]) +{ + RADCLIENT *client; + FILE *fp; + + client = get_client(listener, argc, argv); + if (!client) { return 0; } - variables = cf_section_parse_table(mi->cs); - if (!variables) { - cprintf(listener, "ERROR: Cannot find configuration for module\n"); + if (!client->cs) return 1; + + fp = fdopen(dup(listener->fd), "a"); + if (!fp) { + cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno)); return 0; } - rcode = -1; - for (i = 0; variables[i].name != NULL; i++) { - /* - * FIXME: Recurse into sub-types somehow... - */ - if (variables[i].type == PW_TYPE_SUBSECTION) continue; + cf_section2file(fp, client->cs); + fclose(fp); - if (strcmp(variables[i].name, argv[1]) == 0) { - rcode = i; - break; + return 1; +} + +#ifdef WITH_PROXY +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 [proto]\n"); + return NULL; + } + + if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) { + cprintf(listener, "ERROR: Failed parsing IP address; %s\n", + fr_strerror()); + return NULL; + } + + port = atoi(argv[1]); + + 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 } - if (rcode < 0) { - cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]); + home = home_server_find(&ipaddr, port, proto); + if (!home) { + cprintf(listener, "ERROR: No such home server\n"); + return NULL; + } + + return home; +} + +static int command_show_home_server_config(rad_listen_t *listener, int argc, char *argv[]) +{ + home_server *home; + FILE *fp; + + home = get_home_server(listener, argc, argv, NULL); + if (!home) { return 0; } - i = rcode; /* just to be safe */ + if (!home->cs) return 1; - /* - * It's not part of the dynamic configuration. The module - * needs to re-parse && validate things. - */ - if (variables[i].data) { - cprintf(listener, "ERROR: Variable cannot be dynamically updated\n"); + fp = fdopen(dup(listener->fd), "a"); + if (!fp) { + cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno)); return 0; } - data = ((char *) mi->insthandle) + variables[i].offset; + cf_section2file(fp, home->cs); + fclose(fp); - cp = cf_pair_find(mi->cs, argv[1]); - if (!cp) return 0; + return 1; +} - /* - * Replace the OLD value in the configuration file with - * the NEW value. - * - * FIXME: Parse argv[2] depending on it's data type! - * If it's a string, look for leading single/double quotes, - * end then call tokenize functions??? - */ - cf_pair_replace(mi->cs, cp, argv[2]); +extern void revive_home_server(void *ctx); +extern void mark_home_server_dead(home_server *home, struct timeval *when); - rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, - data, argv[2]); - if (rcode < 0) { - cprintf(listener, "ERROR: Failed to parse value\n"); +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 [proto] \n"); return 0; } - return 1; /* success */ -} + home = get_home_server(listener, argc, argv, &last); + if (!home) { + return 0; + } + if (strcmp(argv[last], "alive") == 0) { + revive_home_server(home); -static fr_command_table_t command_table_set_module[] = { - { "config", - "set module config variable value - set configuration for ", - command_set_module_config, NULL }, + } else if (strcmp(argv[last], "dead") == 0) { + struct timeval now; - { NULL, NULL, NULL, NULL } -}; + gettimeofday(&now, NULL); /* we do this WAY too ofetn */ + mark_home_server_dead(home, &now); + } else { + cprintf(listener, "ERROR: Unknown state \"%s\"\n", argv[last]); + return 0; + } -static fr_command_table_t command_table_set[] = { - { "module", NULL, NULL, command_table_set_module }, + return 1; +} - { NULL, NULL, NULL, NULL } -}; +static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[]) +{ + home_server *home; + home = get_home_server(listener, argc, argv, NULL); + if (!home) { + return 0; + } -static fr_command_table_t command_table[] = { - { "debug", - "debug - debugging commands", - NULL, command_table_debug }, - { "hup", - "hup [module] - sends a HUP signal to the server, or optionally to one module", - command_hup, NULL }, - { "terminate", - "terminate - terminates the server, and causes it to exit", - command_terminate, NULL }, - { "show", NULL, NULL, command_table_show }, - { "set", NULL, NULL, command_table_set }, + switch (home->state) { + case HOME_STATE_ALIVE: + cprintf(listener, "alive\n"); + break; - { NULL, NULL, NULL, NULL } -}; + case HOME_STATE_IS_DEAD: + cprintf(listener, "dead\n"); + break; + case HOME_STATE_ZOMBIE: + cprintf(listener, "zombie\n"); + break; + + default: + cprintf(listener, "unknown\n"); + break; + } + + return 1; +} +#endif /* - * FIXME: Unix domain sockets! + * For encode/decode stuff */ -static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) +static int null_socket_dencode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request) { - fr_command_socket_t *sock; + return 0; +} + +static int null_socket_send(UNUSED rad_listen_t *listener, REQUEST *request) +{ + char *output_file; + FILE *fp; + VALUE_PAIR *vp; + + output_file = request_data_reference(request, null_socket_send, 0); + if (!output_file) { + radlog(L_ERR, "WARNING: No output file for injected packet %d", + request->number); + return 0; + } + + fp = fopen(output_file, "w"); + if (!fp) { + radlog(L_ERR, "Failed to send injected file to %s: %s", + output_file, strerror(errno)); + return 0; + } + + if (request->reply->code != 0) { + const char *what = "reply"; + char buffer[1024]; + + if (request->reply->code < FR_MAX_PACKET_CODE) { + what = fr_packet_codes[request->reply->code]; + } + + fprintf(fp, "%s\n", what); + + if (debug_flag) { + request->radlog(L_DBG, 0, request, + "Injected %s packet to host %s port 0 code=%d, id=%d", + what, + inet_ntop(request->reply->src_ipaddr.af, + &request->reply->src_ipaddr.ipaddr, + buffer, sizeof(buffer)), + request->reply->code, request->reply->id); + } + + for (vp = request->reply->vps; vp != NULL; vp = vp->next) { + vp_prints(buffer, sizeof(buffer), vp); + fprintf(fp, "%s\n", buffer); + if (debug_flag) { + request->radlog(L_DBG, 0, request, "\t%s", + buffer); + } + } + } + fclose(fp); + + return 0; +} + +static int command_inject_to(rad_listen_t *listener, int argc, char *argv[]) +{ + int port; + RAD_LISTEN_TYPE type; + fr_command_socket_t *sock = listener->data; + fr_ipaddr_t ipaddr; + rad_listen_t *found = NULL; + + if (argc < 1) { + cprintf(listener, "ERROR: Must specify [auth/acct]\n"); + return 0; + } + + if (strcmp(argv[0], "auth") == 0) { + type = RAD_LISTEN_AUTH; + + } else if (strcmp(argv[0], "acct") == 0) { +#ifdef WITH_ACCOUNTING + type = RAD_LISTEN_ACCT; +#else + cprintf(listener, "ERROR: This server was built without accounting support.\n"); + return 0; +#endif + + } else { + cprintf(listener, "ERROR: Unknown socket type\n"); + return 0; + } + + if (argc < 3) { + cprintf(listener, "ERROR: No was given\n"); + return 0; + } + + /* + * FIXME: Look for optional arg 4, and bind interface. + */ + + if (ip_hton(argv[1], AF_UNSPEC, &ipaddr) < 0) { + cprintf(listener, "ERROR: Failed parsing IP address; %s\n", + fr_strerror()); + return 0; + } + port = atoi(argv[2]); + + found = listener_find_byipaddr(&ipaddr, port); + if (!found) { + cprintf(listener, "ERROR: Could not find matching listener\n"); + return 0; + } + + sock->inject_listener = found; + sock->dst_ipaddr = ipaddr; + sock->dst_port = port; + + return 1; +} + +static int command_inject_from(rad_listen_t *listener, int argc, char *argv[]) +{ + RADCLIENT *client; + fr_command_socket_t *sock = listener->data; + + if (argc < 1) { + cprintf(listener, "ERROR: No was given\n"); + return 0; + } + + if (!sock->inject_listener) { + cprintf(listener, "ERROR: You must specify \"inject to\" before using \"inject from\"\n"); + return 0; + } + + sock->src_ipaddr.af = AF_UNSPEC; + if (ip_hton(argv[0], AF_UNSPEC, &sock->src_ipaddr) < 0) { + cprintf(listener, "ERROR: Failed parsing IP address; %s\n", + fr_strerror()); + return 0; + } + + client = client_listener_find(sock->inject_listener, &sock->src_ipaddr, + 0); + if (!client) { + cprintf(listener, "ERROR: No such client %s\n", argv[0]); + return 0; + } + sock->inject_client = client; + + return 1; +} + +static int command_inject_file(rad_listen_t *listener, int argc, char *argv[]) +{ + static int inject_id = 0; + int filedone; + fr_command_socket_t *sock = listener->data; + rad_listen_t *fake; + REQUEST *request = NULL; + RADIUS_PACKET *packet; + VALUE_PAIR *vp; + FILE *fp; + RAD_REQUEST_FUNP fun = NULL; + char buffer[2048]; + + if (argc < 2) { + cprintf(listener, "ERROR: You must specify \n"); + return 0; + } + + /* + * Output files always go to the logging directory. + */ + snprintf(buffer, sizeof(buffer), "%s/%s", radlog_dir, argv[1]); + + fp = fopen(argv[0], "r"); + if (!fp ) { + cprintf(listener, "ERROR: Failed opening %s: %s\n", + argv[0], strerror(errno)); + return 0; + } + + vp = readvp2(fp, &filedone, ""); + fclose(fp); + if (!vp) { + cprintf(listener, "ERROR: Failed reading attributes from %s: %s\n", + argv[0], fr_strerror()); + return 0; + } + + fake = rad_malloc(sizeof(*fake)); + memcpy(fake, sock->inject_listener, sizeof(*fake)); + + /* + * Re-write the IO for the listener. + */ + fake->encode = null_socket_dencode; + fake->decode = null_socket_dencode; + fake->send = null_socket_send; + + packet = rad_alloc(0); + packet->src_ipaddr = sock->src_ipaddr; + packet->src_port = 0; + + packet->dst_ipaddr = sock->dst_ipaddr; + packet->dst_port = sock->dst_port; + packet->vps = vp; + packet->id = inject_id++; + + if (fake->type == RAD_LISTEN_AUTH) { + packet->code = PW_AUTHENTICATION_REQUEST; + fun = rad_authenticate; + + } else { +#ifdef WITH_ACCOUNTING + packet->code = PW_ACCOUNTING_REQUEST; + fun = rad_accounting; +#else + cprintf(listener, "ERROR: This server was built without accounting support.\n"); + rad_free(&packet); + free(fake); + return 0; +#endif + } + + if (!received_request(fake, packet, &request, sock->inject_client)) { + cprintf(listener, "ERROR: Failed to inject request. See log file for details\n"); + rad_free(&packet); + free(fake); + return 0; + } + + /* + * Remember what the output file is, and remember to + * delete the fake listener when done. + */ + request_data_add(request, null_socket_send, 0, strdup(buffer), free); + request_data_add(request, null_socket_send, 1, fake, free); + + if (debug_flag) { + request->radlog(L_DBG, 0, request, + "Injected %s packet from host %s port 0 code=%d, id=%d", + fr_packet_codes[packet->code], + inet_ntop(packet->src_ipaddr.af, + &packet->src_ipaddr.ipaddr, + buffer, sizeof(buffer)), + packet->code, packet->id); + + for (vp = packet->vps; vp != NULL; vp = vp->next) { + vp_prints(buffer, sizeof(buffer), vp); + request->radlog(L_DBG, 0, request, "\t%s", buffer); + } + } + + /* + * And go process it. + */ + thread_pool_addrequest(request, fun); + + return 1; +} + + +static fr_command_table_t command_table_inject[] = { + { "to", FR_WRITE, + "inject to - Inject packets to the destination IP and port.", + command_inject_to, NULL }, + + { "from", FR_WRITE, + "inject from - Inject packets as if they came from ", + command_inject_from, NULL }, + + { "file", FR_WRITE, + "inject file - Inject packet from input-file>, with results sent to ", + command_inject_file, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + +static fr_command_table_t command_table_debug[] = { + { "condition", FR_WRITE, + "debug condition [condition] - Enable debugging for requests matching [condition]", + command_debug_condition, NULL }, + + { "level", FR_WRITE, + "debug level - Set debug level to . Higher is more debugging.", + command_debug_level, NULL }, + + { "file", FR_WRITE, + "debug file [filename] - Send all debugging output to [filename]", + command_debug_file, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + +static fr_command_table_t command_table_show_debug[] = { + { "condition", FR_READ, + "show debug condition - Shows current debugging condition.", + command_show_debug_condition, NULL }, + + { "level", FR_READ, + "show debug level - Shows current debugging level.", + command_show_debug_level, NULL }, + + { "file", FR_READ, + "show debug file - Shows current debugging file.", + command_show_debug_file, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + +static fr_command_table_t command_table_show_module[] = { + { "config", FR_READ, + "show module config - show configuration for given module", + command_show_module_config, NULL }, + { "flags", FR_READ, + "show module flags - show other module properties", + command_show_module_flags, NULL }, + { "list", FR_READ, + "show module list - shows list of loaded modules", + command_show_modules, NULL }, + { "methods", FR_READ, + "show module methods - show sections where may be used", + command_show_module_methods, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + +static fr_command_table_t command_table_show_client[] = { + { "config", FR_READ, + "show client config " +#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", + command_show_clients, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + +#ifdef WITH_PROXY +static fr_command_table_t command_table_show_home[] = { + { "config", FR_READ, + "show home_server config [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 [proto] - shows state of given home server", + command_show_home_server_state, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; +#endif + + +static fr_command_table_t command_table_show[] = { + { "client", FR_READ, + "show client - do sub-command of client", + NULL, command_table_show_client }, + { "debug", FR_READ, + "show debug - show debug properties", + NULL, command_table_show_debug }, +#ifdef WITH_PROXY + { "home_server", FR_READ, + "show home_server - do sub-command of home_server", + NULL, command_table_show_home }, +#endif + { "module", FR_READ, + "show module - do sub-command of module", + NULL, command_table_show_module }, + { "uptime", FR_READ, + "show uptime - shows time at which server started", + command_uptime, NULL }, + { "version", FR_READ, + "show version - Prints version of the running server", + command_show_version, NULL }, + { "xml", FR_READ, + "show xml - Prints out configuration as XML", + command_show_xml, NULL }, + { NULL, 0, NULL, NULL, NULL } +}; + + +static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[]) +{ + int i, rcode; + CONF_PAIR *cp; + CONF_SECTION *cs; + module_instance_t *mi; + const CONF_PARSER *variables; + void *data; + + if (argc < 3) { + cprintf(listener, "ERROR: No module name or variable 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 ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) { + cprintf(listener, "ERROR: Cannot change configuration of module as it is cannot be HUP'd.\n"); + return 0; + } + + variables = cf_section_parse_table(mi->cs); + if (!variables) { + cprintf(listener, "ERROR: Cannot find configuration for module\n"); + return 0; + } + + rcode = -1; + for (i = 0; variables[i].name != NULL; i++) { + /* + * FIXME: Recurse into sub-types somehow... + */ + if (variables[i].type == PW_TYPE_SUBSECTION) continue; + + if (strcmp(variables[i].name, argv[1]) == 0) { + rcode = i; + break; + } + } + + if (rcode < 0) { + cprintf(listener, "ERROR: No such variable \"%s\"\n", argv[1]); + return 0; + } + + i = rcode; /* just to be safe */ + + /* + * It's not part of the dynamic configuration. The module + * needs to re-parse && validate things. + */ + if (variables[i].data) { + cprintf(listener, "ERROR: Variable cannot be dynamically updated\n"); + return 0; + } + + data = ((char *) mi->insthandle) + variables[i].offset; + + cp = cf_pair_find(mi->cs, argv[1]); + if (!cp) return 0; + + /* + * Replace the OLD value in the configuration file with + * the NEW value. + * + * FIXME: Parse argv[2] depending on it's data type! + * If it's a string, look for leading single/double quotes, + * end then call tokenize functions??? + */ + cf_pair_replace(mi->cs, cp, argv[2]); + + rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, + data, argv[2]); + if (rcode < 0) { + cprintf(listener, "ERROR: Failed to parse value\n"); + return 0; + } + + 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%u\n", stats->total_requests); + cprintf(listener, "\tresponses\t%u\n", stats->total_responses); + + if (auth) { + cprintf(listener, "\taccepts\t\t%u\n", + stats->total_access_accepts); + cprintf(listener, "\trejects\t\t%u\n", + stats->total_access_rejects); + cprintf(listener, "\tchallenges\t%u\n", + stats->total_access_challenges); + } + + 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 \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[]) +{ + home_server *home; + + if (argc == 0) { + cprintf(listener, "ERROR: Must specify [auth/acct] OR \n"); + return 0; + } + + if (argc == 1) { +#ifdef WITH_ACCOUNTING + if (strcmp(argv[0], "acct") == 0) { + return command_print_stats(listener, + &proxy_acct_stats, 0); + } +#endif + if (strcmp(argv[0], "auth") == 0) { + return command_print_stats(listener, + &proxy_auth_stats, 1); + } + + cprintf(listener, "ERROR: Should specify [auth/acct]\n"); + return 0; + } + + home = get_home_server(listener, argc, argv, NULL); + if (!home) { + return 0; + } + + command_print_stats(listener, &home->stats, + (home->type == HOME_TYPE_AUTH)); + cprintf(listener, "\toutstanding\t%d\n", home->currently_outstanding); + return 1; +} +#endif + +static int command_stats_client(rad_listen_t *listener, int argc, char *argv[]) +{ + int auth = TRUE; + RADCLIENT *client; + + if (argc < 1) { + cprintf(listener, "ERROR: Must specify [auth/acct]\n"); + return 0; + } + + if (strcmp(argv[0], "auth") == 0) { + auth = TRUE; + + } else if (strcmp(argv[0], "acct") == 0) { +#ifdef WITH_ACCOUNTING + auth = FALSE; +#else + cprintf(listener, "ERROR: This server was built without accounting support.\n"); + return 0; +#endif + + } else { + cprintf(listener, "ERROR: Unknown statistics type\n"); + return 0; + } + + /* + * Global results for all client. + */ + if (argc == 1) { +#ifdef WITH_ACCOUNTING + if (!auth) { + return command_print_stats(listener, + &radius_acct_stats, auth); + } +#endif + return command_print_stats(listener, &radius_auth_stats, auth); + } + + client = get_client(listener, argc - 1, argv + 1); + if (!client) { + return 0; + } + +#ifdef WITH_ACCOUNTING + if (!auth) { + return command_print_stats(listener, client->acct, auth); + } +#endif + + return command_print_stats(listener, client->auth, auth); +} + + +static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[]) +{ + RADCLIENT *c; + + if (argc < 1) { + cprintf(listener, "ERROR: is required\n"); + return 0; + } + + /* + * Read the file and generate the client. + */ + c = client_read(argv[0], FALSE, FALSE); + if (!c) { + cprintf(listener, "ERROR: Unknown error reading client file.\n"); + return 0; + } + + if (!client_add(NULL, c)) { + cprintf(listener, "ERROR: Unknown error inserting new client.\n"); + client_free(c); + return 0; + } + + return 1; +} + + +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 - 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 - 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 - Add new client definition from ", + command_add_client_file, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; + + +static fr_command_table_t command_table_add[] = { + { "client", FR_WRITE, + "add client - Add client configuration commands", + NULL, command_table_add_client }, + + { NULL, 0, NULL, NULL, NULL } +}; + + +#ifdef WITH_PROXY +static fr_command_table_t command_table_set_home[] = { + { "state", FR_WRITE, + "set home_server state [proto] [alive|dead] - set state for given home server", + command_set_home_server_state, NULL }, + + { NULL, 0, NULL, NULL, NULL } +}; +#endif + +static fr_command_table_t command_table_set_module[] = { + { "config", FR_WRITE, + "set module config variable value - set configuration for ", + 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_set[] = { + { "module", FR_WRITE, + "set module - set module commands", + NULL, command_table_set_module }, +#ifdef WITH_PROXY + { "home_server", FR_WRITE, + "set home_server - set home server commands", + NULL, command_table_set_home }, +#endif + + { NULL, 0, NULL, NULL, NULL } +}; + + +static fr_command_table_t command_table_stats[] = { + { "client", FR_READ, + "stats client [auth/acct] " +#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 [/auth/acct] - 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 - show statistics for the given detail file", + command_stats_detail, NULL }, +#endif + + { NULL, 0, NULL, NULL, NULL } +}; + +static fr_command_table_t command_table[] = { + { "add", FR_WRITE, NULL, NULL, command_table_add }, + { "debug", FR_WRITE, + "debug - 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 }, + { "inject", FR_WRITE, + "inject - commands to inject packets into a running server", + NULL, command_table_inject }, + { "reconnect", FR_READ, + "reconnect - reconnect to a running server", + NULL, NULL }, /* just here for "help" */ + { "terminate", FR_WRITE, + "terminate - terminates the server, and cause it to exit", + command_terminate, NULL }, + { "set", FR_WRITE, NULL, NULL, command_table_set }, + { "show", FR_READ, NULL, NULL, command_table_show }, + { "stats", FR_READ, NULL, NULL, command_table_stats }, + + { NULL, 0, NULL, NULL, 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. + * + * FIXME: TCP + SSL, after RadSec is in. + */ +static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) +{ + fr_command_socket_t *sock; + + if (check_config) return 0; sock = this->data; @@ -788,6 +1909,9 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) 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; @@ -823,6 +1947,17 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) #endif + if (!sock->mode_name) { + sock->mode = FR_READ; + } else { + sock->mode = fr_str2int(mode_names, sock->mode_name, 0); + if (!sock->mode) { + radlog(L_ERR, "Invalid mode name \"%s\"", + sock->mode_name); + return -1; + } + } + /* * FIXME: check for absolute pathnames? * check for uid/gid on the other end... @@ -852,6 +1987,8 @@ static int command_socket_print(rad_listen_t *this, char *buffer, size_t bufsize static int str2argv(char *str, char **argv, int max_argc) { int argc = 0; + size_t len; + char buffer[1024]; while (*str) { if (argc >= max_argc) return argc; @@ -871,7 +2008,29 @@ static int str2argv(char *str, char **argv, int max_argc) if (!*str) return argc; - argv[argc] = str; + if ((*str == '\'') || (*str == '"')) { + char *p = str; + FR_TOKEN token; + + token = gettoken((const char **) &p, buffer, + sizeof(buffer)); + if ((token != T_SINGLE_QUOTED_STRING) && + (token != T_DOUBLE_QUOTED_STRING)) { + return -1; + } + + len = strlen(buffer); + if (len >= (size_t) (p - str)) { + return -1; + } + + memcpy(str, buffer, len + 1); + argv[argc] = str; + str = p; + + } else { + argv[argc] = str; + } argc++; while (*str && @@ -884,6 +2043,26 @@ static int str2argv(char *str, char **argv, int max_argc) return argc; } +static void print_help(rad_listen_t *listener, + fr_command_table_t *table, int recursive) +{ + int i; + + for (i = 0; table[i].command != NULL; i++) { + if (table[i].help) { + cprintf(listener, "%s\n", + table[i].help); + } else { + cprintf(listener, "%s - do sub-command of %s\n", + table[i].command, table[i].command); + } + + if (recursive && table[i].table) { + print_help(listener, table[i].table, recursive); + } + } +} + #define MAX_ARGV (16) /* @@ -926,8 +2105,7 @@ static int command_domain_recv(rad_listen_t *listener, */ if ((co->offset == 0) && (co->buffer[0] == 0x04)) { close_socket: - listener->status = RAD_LISTEN_STATUS_CLOSED; - event_new_fd(listener); + command_close_socket(listener); return 0; } @@ -975,8 +2153,16 @@ static int command_domain_recv(rad_listen_t *listener, co->offset++; } while (1); + DEBUG("radmin> %s", co->buffer); + argc = str2argv(co->buffer, my_argv, MAX_ARGV); - if (argc == 0) goto do_next; + if (argc == 0) goto do_next; /* empty strings are OK */ + + if (argc < 0) { + cprintf(listener, "ERROR: Failed parsing command.\n"); + goto do_next; + } + argv = my_argv; for (len = 0; len <= co->offset; len++) { @@ -1023,6 +2209,15 @@ static int command_domain_recv(rad_listen_t *listener, len = 0; for (i = 0; table[i].command != NULL; i++) { if (strcmp(table[i].command, argv[0]) == 0) { + /* + * Check permissions. + */ + if (((co->mode & FR_WRITE) == 0) && + ((table[i].mode & FR_WRITE) != 0)) { + cprintf(listener, "ERROR: You do not have write permission. See \"mode = rw\" in the \"listen\" section for this socket.\n"); + goto do_next; + } + if (table[i].table) { /* * This is the last argument, but @@ -1040,6 +2235,13 @@ static int command_domain_recv(rad_listen_t *listener, 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; + } + len = 1; rcode = table[i].func(listener, argc - 1, argv + 1); @@ -1053,20 +2255,20 @@ static int command_domain_recv(rad_listen_t *listener, if (!len) { if ((strcmp(argv[0], "help") == 0) || (strcmp(argv[0], "?") == 0)) { + int recursive; + do_help: - for (i = 0; table[i].command != NULL; i++) { - if (table[i].help) { - cprintf(listener, "%s\n", - table[i].help); - } else { - cprintf(listener, "%s - do sub-command of %s\n", - table[i].command, table[i].command); - } + if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) { + recursive = TRUE; + } else { + recursive = FALSE; } + + print_help(listener, table, recursive); goto do_next; } - cprintf(listener, "ERROR: Unknown command \"%s\"\r\n", + cprintf(listener, "ERROR: Unknown command \"%s\"\n", argv[0]); } @@ -1099,6 +2301,9 @@ static int command_domain_accept(rad_listen_t *listener, 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) { @@ -1110,7 +2315,7 @@ static int command_domain_accept(rad_listen_t *listener, } DEBUG2(" ... failed to accept connection."); - return -1; + return 0; } /* @@ -1124,21 +2329,21 @@ static int command_domain_accept(rad_listen_t *listener, 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; } } @@ -1150,14 +2355,14 @@ static int command_domain_accept(rad_listen_t *listener, 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; } @@ -1165,7 +2370,7 @@ static int command_domain_accept(rad_listen_t *listener, * 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 @@ -1180,6 +2385,7 @@ static int command_domain_accept(rad_listen_t *listener, sock->offset = 0; sock->user[0] = '\0'; sock->path = ((fr_command_socket_t *) listener->data)->path; + sock->mode = ((fr_command_socket_t *) listener->data)->mode; this->fd = newfd; this->recv = command_domain_recv;