int main(int argc, char **argv) { int argval, quiet = 0; int done_license = 0; int sockfd; uint32_t magic, needed; char *line = NULL; ssize_t len, size; char const *file = NULL; char const *name = "radiusd"; char *p, buffer[65536]; char const *input_file = NULL; FILE *inputfp = stdin; char const *output_file = NULL; char const *server = NULL; char *commands[MAX_COMMANDS]; int num_commands = -1; #ifndef NDEBUG fr_fault_setup(getenv("PANIC_ACTION"), argv[0]); #endif talloc_set_log_stderr(); outputfp = stdout; /* stdout is not a constant value... */ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; while ((argval = getopt(argc, argv, "d:hi:e:Ef:n:o:qs:S")) != EOF) { switch(argval) { case 'd': if (file) { fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname); exit(1); } if (server) { fprintf(stderr, "%s: -d and -s cannot be used together.\n", progname); exit(1); } radius_dir = optarg; break; case 'e': num_commands++; /* starts at -1 */ if (num_commands >= MAX_COMMANDS) { fprintf(stderr, "%s: Too many '-e'\n", progname); exit(1); } commands[num_commands] = optarg; break; case 'E': echo = true; break; case 'f': radius_dir = NULL; file = optarg; break; default: case 'h': usage(0); break; case 'i': if (strcmp(optarg, "-") != 0) { input_file = optarg; } quiet = 1; break; case 'n': name = optarg; break; case 'o': if (strcmp(optarg, "-") != 0) { output_file = optarg; } quiet = 1; break; case 'q': quiet = 1; break; case 's': if (file) { fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname); usage(1); } radius_dir = NULL; server = optarg; break; case 'S': secret = NULL; break; } } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radmin"); exit(1); } if (radius_dir) { int rcode; CONF_SECTION *cs, *subcs; file = NULL; /* MUST read it from the conffile now */ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name); cs = cf_file_read(buffer); if (!cs) { fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, buffer); usage(1); } subcs = NULL; while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) { char const *value; CONF_PAIR *cp = cf_pair_find(subcs, "type"); if (!cp) continue; value = cf_pair_value(cp); if (!value) continue; if (strcmp(value, "control") != 0) continue; /* * Now find the socket name (sigh) */ rcode = cf_item_parse(subcs, "socket", PW_TYPE_STRING_PTR, &file, NULL); if (rcode < 0) { fprintf(stderr, "%s: Failed parsing listen section\n", progname); exit(1); } if (!file) { fprintf(stderr, "%s: No path given for socket\n", progname); usage(1); } break; } if (!file) { fprintf(stderr, "%s: Could not find control socket in %s\n", progname, buffer); exit(1); } } if (input_file) { inputfp = fopen(input_file, "r"); if (!inputfp) { fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, strerror(errno)); exit(1); } } if (output_file) { outputfp = fopen(output_file, "w"); if (!outputfp) { fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, strerror(errno)); exit(1); } } /* * Check if stdin is a TTY only if input is from stdin */ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = 1; #ifdef USE_READLINE if (!quiet) { #ifdef USE_READLINE_HISTORY using_history(); #endif rl_bind_key('\t', rl_insert); } #endif reconnect: if (file) { /* * FIXME: Get destination from command line, if possible? */ sockfd = fr_domain_socket(file); if (sockfd < 0) { exit(1); } } else { sockfd = client_socket(server); } /* * Read initial magic && version information. */ for (size = 0; size < 8; size += len) { len = read(sockfd, buffer + size, 8 - size); if (len < 0) { fprintf(stderr, "%s: Error reading initial data from socket: %s\n", progname, strerror(errno)); exit(1); } } memcpy(&magic, buffer, 4); magic = ntohl(magic); if (magic != 0xf7eead15) { fprintf(stderr, "%s: Socket %s is not FreeRADIUS administration socket\n", progname, file); exit(1); } memcpy(&magic, buffer + 4, 4); magic = ntohl(magic); if (!server) { needed = 1; } else { needed = 2; } if (magic != needed) { fprintf(stderr, "%s: Socket version mismatch: Need %d, got %d\n", progname, needed, magic); exit(1); } if (server && secret) do_challenge(sockfd); /* * Run one command. */ if (num_commands >= 0) { int i; for (i = 0; i <= num_commands; i++) { size = run_command(sockfd, commands[i], buffer, sizeof(buffer)); if (size < 0) exit(1); if (buffer[0]) { fputs(buffer, outputfp); fprintf(outputfp, "\n"); fflush(outputfp); } } exit(0); } if (!done_license && !quiet) { printf("%s - FreeRADIUS Server administration tool.\n", radmin_version); printf("Copyright (C) 2008-2014 The FreeRADIUS server project and contributors.\n"); printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"); printf("PARTICULAR PURPOSE.\n"); printf("You may redistribute copies of FreeRADIUS under the terms of the\n"); printf("GNU General Public License v2.\n"); done_license = 1; } /* * FIXME: Do login? */ while (1) { #ifndef USE_READLINE if (!quiet) { printf("radmin> "); fflush(stdout); } #else if (!quiet) { line = readline("radmin> "); if (!line) break; if (!*line) { free(line); continue; } #ifdef USE_READLINE_HISTORY add_history(line); #endif } else /* quiet, or no readline */ #endif { line = fgets(buffer, sizeof(buffer), inputfp); if (!line) break; p = strchr(buffer, '\n'); if (!p) { fprintf(stderr, "%s: Input line too long\n", progname); exit(1); } *p = '\0'; /* * Strip off leading spaces. */ for (p = line; *p != '\0'; p++) { if ((p[0] == ' ') || (p[0] == '\t')) { line = p + 1; continue; } if (p[0] == '#') { line = NULL; break; } break; } /* * Comments: keep going. */ if (!line) continue; /* * Strip off CR / LF */ for (p = line; *p != '\0'; p++) { if ((p[0] == '\r') || (p[0] == '\n')) { p[0] = '\0'; break; } } } if (strcmp(line, "reconnect") == 0) { close(sockfd); line = NULL; goto reconnect; } if (memcmp(line, "secret ", 7) == 0) { if (!secret) { secret = line + 7; do_challenge(sockfd); } line = NULL; continue; } /* * Exit, done, etc. */ if ((strcmp(line, "exit") == 0) || (strcmp(line, "quit") == 0)) { break; } if (server && !secret) { fprintf(stderr, "ERROR: You must enter 'secret <SECRET>' before running any commands\n"); line = NULL; continue; } size = run_command(sockfd, line, buffer, sizeof(buffer)); if (size <= 0) break; /* error, or clean exit */ if (size == 1) continue; /* no output. */ fputs(buffer, outputfp); fflush(outputfp); fprintf(outputfp, "\n"); } fprintf(outputfp, "\n"); return 0; }
int main(int argc, char **argv) { int argval; bool quiet = false; int sockfd = -1; char *line = NULL; ssize_t len; char const *file = NULL; char const *name = "radiusd"; char *p, buffer[65536]; char const *input_file = NULL; FILE *inputfp = stdin; char const *output_file = NULL; char const *server = NULL; char const *radius_dir = RADIUS_DIR; char const *dict_dir = DICTDIR; char *commands[MAX_COMMANDS]; int num_commands = -1; #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("radmin"); exit(EXIT_FAILURE); } #endif talloc_set_log_stderr(); outputfp = stdout; /* stdout is not a constant value... */ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) { progname = argv[0]; } else { progname++; } while ((argval = getopt(argc, argv, "d:D:hi:e:Ef:n:o:qs:S")) != EOF) { switch (argval) { case 'd': if (file) { fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname); exit(1); } if (server) { fprintf(stderr, "%s: -d and -s cannot be used together.\n", progname); exit(1); } radius_dir = optarg; break; case 'D': dict_dir = optarg; break; case 'e': num_commands++; /* starts at -1 */ if (num_commands >= MAX_COMMANDS) { fprintf(stderr, "%s: Too many '-e'\n", progname); exit(1); } commands[num_commands] = optarg; break; case 'E': echo = true; break; case 'f': radius_dir = NULL; file = optarg; break; default: case 'h': usage(0); break; case 'i': if (strcmp(optarg, "-") != 0) { input_file = optarg; } quiet = true; break; case 'n': name = optarg; break; case 'o': if (strcmp(optarg, "-") != 0) { output_file = optarg; } quiet = true; break; case 'q': quiet = true; break; case 's': if (file) { fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname); usage(1); } radius_dir = NULL; server = optarg; break; case 'S': secret = NULL; break; } } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radmin"); exit(1); } if (radius_dir) { int rcode; CONF_SECTION *cs, *subcs; file = NULL; /* MUST read it from the conffile now */ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name); /* * Need to read in the dictionaries, else we may get * validation errors when we try and parse the config. */ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radmin"); exit(64); } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radmin"); exit(64); } cs = cf_file_read(buffer); if (!cs) { fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, buffer); usage(1); } subcs = NULL; while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) { char const *value; CONF_PAIR *cp = cf_pair_find(subcs, "type"); if (!cp) continue; value = cf_pair_value(cp); if (!value) continue; if (strcmp(value, "control") != 0) continue; /* * Now find the socket name (sigh) */ rcode = cf_item_parse(subcs, "socket", FR_ITEM_POINTER(PW_TYPE_STRING, &file), NULL); if (rcode < 0) { fprintf(stderr, "%s: Failed parsing listen section\n", progname); exit(1); } if (!file) { fprintf(stderr, "%s: No path given for socket\n", progname); usage(1); } break; } if (!file) { fprintf(stderr, "%s: Could not find control socket in %s\n", progname, buffer); exit(1); } } if (input_file) { inputfp = fopen(input_file, "r"); if (!inputfp) { fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno)); exit(1); } } if (output_file) { outputfp = fopen(output_file, "w"); if (!outputfp) { fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, fr_syserror(errno)); exit(1); } } if (!file && !server) { fprintf(stderr, "%s: Must use one of '-d' or '-f' or '-s'\n", progname); exit(1); } /* * Check if stdin is a TTY only if input is from stdin */ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = true; #ifdef USE_READLINE if (!quiet) { #ifdef USE_READLINE_HISTORY using_history(); #endif rl_bind_key('\t', rl_insert); } #endif /* * Prevent SIGPIPEs from terminating the process */ signal(SIGPIPE, SIG_IGN); if (do_connect(&sockfd, file, server) < 0) exit(1); /* * Run one command. */ if (num_commands >= 0) { int i; for (i = 0; i <= num_commands; i++) { len = run_command(sockfd, commands[i], buffer, sizeof(buffer)); if (len < 0) exit(1); if (buffer[0]) { fputs(buffer, outputfp); fprintf(outputfp, "\n"); fflush(outputfp); } } exit(0); } if (!quiet) { printf("%s - FreeRADIUS Server administration tool.\n", radmin_version); printf("Copyright (C) 2008-2014 The FreeRADIUS server project and contributors.\n"); printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"); printf("PARTICULAR PURPOSE.\n"); printf("You may redistribute copies of FreeRADIUS under the terms of the\n"); printf("GNU General Public License v2.\n"); } /* * FIXME: Do login? */ while (1) { #ifndef USE_READLINE if (!quiet) { printf("radmin> "); fflush(stdout); } #else if (!quiet) { line = readline("radmin> "); if (!line) break; if (!*line) { free(line); continue; } #ifdef USE_READLINE_HISTORY add_history(line); #endif } else /* quiet, or no readline */ #endif { line = fgets(buffer, sizeof(buffer), inputfp); if (!line) break; p = strchr(buffer, '\n'); if (!p) { fprintf(stderr, "%s: Input line too long\n", progname); exit(1); } *p = '\0'; /* * Strip off leading spaces. */ for (p = line; *p != '\0'; p++) { if ((p[0] == ' ') || (p[0] == '\t')) { line = p + 1; continue; } if (p[0] == '#') { line = NULL; break; } break; } /* * Comments: keep going. */ if (!line) continue; /* * Strip off CR / LF */ for (p = line; *p != '\0'; p++) { if ((p[0] == '\r') || (p[0] == '\n')) { p[0] = '\0'; break; } } } if (strcmp(line, "reconnect") == 0) { if (do_connect(&sockfd, file, server) < 0) exit(1); line = NULL; continue; } if (memcmp(line, "secret ", 7) == 0) { if (!secret) { secret = line + 7; do_challenge(sockfd); } line = NULL; continue; } /* * Exit, done, etc. */ if ((strcmp(line, "exit") == 0) || (strcmp(line, "quit") == 0)) { break; } if (server && !secret) { fprintf(stderr, "ERROR: You must enter 'secret <SECRET>' before running any commands\n"); line = NULL; continue; } len = run_command(sockfd, line, buffer, sizeof(buffer)); if ((len < 0) && (do_connect(&sockfd, file, server) < 0)) { fprintf(stderr, "Reconnecting..."); exit(1); } else if (len == 0) break; else if (len == 1) continue; /* no output. */ fputs(buffer, outputfp); fflush(outputfp); fprintf(outputfp, "\n"); } fprintf(outputfp, "\n"); return 0; }
/* * %{poke:sql.foo=bar} */ static ssize_t xlat_poke(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen) { int i; void *data, *base; char *p, *q; module_instance_t *mi; char *buffer; CONF_SECTION *modules; CONF_PAIR *cp; CONF_PARSER const *variables; size_t len; rad_assert(outlen > 1); rad_assert(request != NULL); rad_assert(fmt != NULL); rad_assert(out != NULL); *out = '\0'; modules = cf_section_sub_find(request->root->config, "modules"); if (!modules) return 0; buffer = talloc_strdup(request, fmt); if (!buffer) return 0; p = strchr(buffer, '.'); if (!p) return 0; *(p++) = '\0'; mi = module_find(modules, buffer); if (!mi) { RDEBUG("Failed finding module '%s'", buffer); fail: talloc_free(buffer); return 0; } q = strchr(p, '='); if (!q) { RDEBUG("Failed finding '=' in string '%s'", fmt); goto fail; } *(q++) = '\0'; if (strchr(p, '.') != NULL) { RDEBUG("Can't do sub-sections right now"); goto fail; } cp = cf_pair_find(mi->cs, p); if (!cp) { RDEBUG("No such item '%s'", p); goto fail; } /* * Copy the old value to the output buffer, that way * tests can restore it later, if they need to. */ len = strlcpy(out, cf_pair_value(cp), outlen); if (cf_pair_replace(mi->cs, cp, q) < 0) { RDEBUG("Failed replacing pair"); goto fail; } base = mi->insthandle; variables = mi->entry->module->config; /* * Handle the known configuration parameters. */ for (i = 0; variables[i].name != NULL; i++) { int ret; if (variables[i].type == PW_TYPE_SUBSECTION) continue; /* else it's a CONF_PAIR */ /* * Not the pair we want. Skip it. */ if (strcmp(variables[i].name, p) != 0) continue; if (variables[i].data) { data = variables[i].data; /* prefer this. */ } else if (base) { data = ((char *)base) + variables[i].offset; } else { DEBUG2("Internal sanity check 2 failed in cf_section_parse"); goto fail; } /* * Parse the pair we found, or a default value. */ ret = cf_item_parse(mi->cs, variables[i].name, variables[i].type, data, variables[i].dflt); if (ret < 0) { DEBUG2("Failed inserting new value into module instance data"); goto fail; } break; /* we found it, don't do any more */ } talloc_free(buffer); return len; }