The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
unit_test_map.c
Go to the documentation of this file.
1 /*
2  * unit_test_map.c Map debugging tool.
3  *
4  * Version: $Id: 847ac5eb8fe5f22cbf67c4c682b1f2a5f7551ed6 $
5  *
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.
10  *
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.
15  *
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
19  *
20  * @copyright 2015 Alan DeKok (aland@freeradius.org)
21  */
22 
23 RCSID("$Id: 847ac5eb8fe5f22cbf67c4c682b1f2a5f7551ed6 $")
24 
25 #include <freeradius-devel/server/cf_file.h>
26 #include <freeradius-devel/server/main_config.h>
27 #include <freeradius-devel/server/modpriv.h>
28 #include <freeradius-devel/server/module_rlm.h>
29 #include <freeradius-devel/util/atexit.h>
30 #include <freeradius-devel/util/file.h>
31 
32 #include <freeradius-devel/util/conf.h>
33 
34 #include <ctype.h>
35 
36 #ifdef HAVE_GETOPT_H
37 # include <getopt.h>
38 #endif
39 
40 #include <assert.h>
41 
42 #include <freeradius-devel/server/log.h>
43 
44 #define EXIT_WITH_FAILURE \
45 do { \
46  ret = EXIT_FAILURE; \
47  goto cleanup; \
48 } while (0)
49 
50 static fr_dict_t const *dict_freeradius;
51 static fr_dict_t const *dict_radius;
52 
55  { .out = &dict_freeradius, .proto = "freeradius" },
56  { .out = &dict_radius, .proto = "radius" },
57  { NULL }
58 };
59 
60 
61 static NEVER_RETURNS void usage(char *argv[])
62 {
63  fprintf(stderr, "usage: %s [OPTS] filename ...\n", argv[0]);
64  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
65  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
66  fprintf(stderr, " -x Debugging mode.\n");
67  fprintf(stderr, " -M Show program version information.\n");
68  fprintf(stderr, " -r <receipt_file> Create the <receipt_file> as a 'success' exit.\n");
69 
70  fr_exit_now(EXIT_SUCCESS);
71 }
72 
73 static int process_file(char const *filename)
74 {
75  int rcode;
76  char const *name1, *name2;
77  CONF_SECTION *cs;
78  map_list_t list;
79  map_t *map = NULL;
80  char buffer[8192];
81 
83 
84  tmpl_rules_t parse_rules = {
85  .attr = {
87  .list_def = request_attr_request,
88  .allow_foreign = false, /* tests are in the RADIUS dictionary */
89  }
90  };
91 
92  map_list_init(&list);
93 
94  config = main_config_alloc(NULL);
95  if (!config) {
96  fprintf(stderr, "Failed allocating main config");
97  return EXIT_FAILURE;
98  }
99  config->root_cs = cf_section_alloc(config, NULL, "main", NULL);
100  if ((cf_file_read(config->root_cs, filename) < 0) || (cf_section_pass2(config->root_cs) < 0)) {
101  fprintf(stderr, "unit_test_map: Failed parsing %s\n", filename);
102  return EXIT_FAILURE;
103  }
104 
105  main_config_name_set_default(config, "unit_test_map", false);
106 
107  /*
108  * Always has to be an "update" section.
109  */
110  cs = cf_section_find(config->root_cs, "update", CF_IDENT_ANY);
111  if (!cs) {
112  talloc_free(config->root_cs);
113  return EXIT_FAILURE;
114  }
115 
116  /*
117  * Convert the update section to a list of maps.
118  */
119  rcode = map_afrom_cs(cs, &list, cs, &parse_rules, &parse_rules, unlang_fixup_update, NULL, 128);
120  if (rcode < 0) {
121  cf_log_perr(cs, "map_afrom_cs failed");
122  return EXIT_FAILURE; /* message already printed */
123  }
124  if (map_list_empty(&list)) {
125  cf_log_err(cs, "'update' sections cannot be empty");
126  return EXIT_FAILURE;
127  }
128 
129  buffer[0] = '\t';
130 
131  name1 = cf_section_name1(cs);
132  name2 = cf_section_name2(cs);
133 
134  /*
135  * And print it all out.
136  */
137  if (!name2) {
138  printf("%s {\n", name1);
139  } else {
140  printf("%s %s {\n", name1, name2);
141  }
142 
143  while ((map = map_list_next(&list, map))) {
144  map_print(&FR_SBUFF_OUT(buffer + 1, sizeof(buffer) - 1), map);
145  puts(buffer);
146  }
147  printf("}\n");
148 
149  talloc_free(config->root_cs);
151 
152  return EXIT_SUCCESS;
153 }
154 
155 /**
156  *
157  * @hidecallgraph
158  */
159 int main(int argc, char *argv[])
160 {
161  int c, ret = EXIT_SUCCESS;
162  char const *raddb_dir = RADDBDIR;
163  char const *dict_dir = DICTDIR;
164  fr_dict_t *dict = NULL;
165  char const *receipt_file = NULL;
166 
167  TALLOC_CTX *autofree;
168 
169  /*
170  * Must be called first, so the handler is called last
171  */
173 
175 
176 #ifndef NDEBUG
177  if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
178  fr_perror("unit_test_map");
179  fr_exit(EXIT_FAILURE);
180  }
181 #else
183 #endif
184 
185  /*
186  * Sync wallclock and cpu time so that we can find
187  * uses of fr_time_[to|from]_* where
188  * fr_unix_time_[to|from]_* should be used.
189  *
190  * If the wallclock/cpu offset is 0, then both sets
191  * of macros produce the same result.
192  */
193  fr_time_start();
194 
195  while ((c = getopt(argc, argv, "d:D:xMhr:")) != -1) switch (c) {
196  case 'd':
197  raddb_dir = optarg;
198  break;
199 
200  case 'D':
201  dict_dir = optarg;
202  break;
203 
204  case 'x':
205  fr_debug_lvl++;
206  break;
207 
208  case 'M':
209  talloc_enable_leak_report();
210  break;
211 
212  case 'r':
213  receipt_file = optarg;
214  break;
215 
216  case 'h':
217  default:
218  usage(argv);
219  }
220  argc -= (optind - 1);
221  argv += (optind - 1);
222 
223  if (receipt_file && (fr_unlink(receipt_file) < 0)) {
224  fr_perror("unit_test_map");
226  }
227 
228  /*
229  * Mismatch between the binary and the libraries it depends on
230  */
232  fr_perror("unit_test_map");
234  }
235 
236  if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
237  fr_perror("unit_test_map");
239  }
240 
242  fr_perror("unit_test_map");
244  }
245 
246  /*
247  * Load the custom dictionary
248  */
249  if (fr_dict_read(dict, raddb_dir, FR_DICTIONARY_FILE) == -1) {
250  fr_strerror_const_push("Failed to initialize the dictionaries");
251  fr_perror("unit_test_map");
253  }
254 
256  fr_perror("unit_test_map");
258  }
259 
260  if (request_global_init() < 0) {
261  fr_perror("unit_test_module");
263  }
264 
265  if (argc < 2) {
266  ret = process_file("-");
267 
268  } else {
269  ret = process_file(argv[1]);
270  }
271 
272  if (ret < 0) ret = 1; /* internal to Unix process return code */
273 
274 cleanup:
275  /*
276  * Ensure all thread local memory is cleaned up
277  * at the appropriate time. This emulates what's
278  * done with worker/network threads in the
279  * scheduler.
280  */
282 
284 
285  /*
286  * Free any autoload dictionaries
287  */
289  fr_perror("unit_test_map");
290  ret = EXIT_FAILURE;
291  }
292 
293  if (fr_dict_free(&dict, __FILE__) < 0) {
294  fr_perror("unit_test_map");
295  ret = EXIT_FAILURE;
296  }
297 
298  if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
299  fr_perror("unit_test_map");
300  ret = EXIT_FAILURE;
301  }
302 
303  /*
304  * Ensure our atexit handlers run before any other
305  * atexit handlers registered by third party libraries.
306  */
308 
309  return ret;
310 }
static int const char char buffer[256]
Definition: acutest.h:574
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition: atexit.c:160
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition: atexit.c:286
#define fr_atexit_thread_trigger_all(...)
Definition: atexit.h:233
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
int cf_file_read(CONF_SECTION *cs, char const *filename)
Definition: cf_file.c:3010
int cf_section_pass2(CONF_SECTION *cs)
Definition: cf_file.c:757
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:970
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1112
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_log_perr(_cf, _fmt,...)
Definition: cf_util.h:272
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:137
#define CF_IDENT_ANY
Definition: cf_util.h:78
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition: debug.c:1180
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:1215
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition: debug.h:226
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:232
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name, char const *dependent)
(Re-)Initialize the special internal dictionary
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:3581
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Definition: dict_util.c:3984
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
Definition: file.c:348
ssize_t fr_touch(int *fd_out, char const *filename, mode_t mode, bool mkdir, mode_t dir_mode)
Create an empty file.
Definition: file.c:304
int map_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map.
Definition: map.c:1015
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition: map.c:2297
talloc_free(reap)
int fr_debug_lvl
Definition: log.c:42
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
Definition: main_config.c:840
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
Definition: main_config.c:1000
Main server configuration.
Definition: main_config.h:51
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
Definition: compile.c:553
static const conf_parser_t config[]
Definition: base.c:188
static TALLOC_CTX * autofree
Definition: radclient-ng.c:104
static bool cleanup
Definition: radsniff.c:60
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
void request_global_free(void)
Definition: request.c:713
int request_global_init(void)
Definition: request.c:698
#define FR_SBUFF_OUT(_start, _len_or_end)
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
Value pair map.
Definition: map.h:77
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition: talloc.h:51
int fr_time_start(void)
Initialize the local time.
Definition: time.c:150
int main(int argc, char *argv[])
fr_dict_autoload_t unit_test_module_dict[]
Definition: unit_test_map.c:54
static fr_dict_t const * dict_freeradius
Definition: unit_test_map.c:50
static int process_file(char const *filename)
Definition: unit_test_map.c:73
static fr_dict_t const * dict_radius
Definition: unit_test_map.c:51
static NEVER_RETURNS void usage(char *argv[])
Definition: unit_test_map.c:61
#define EXIT_WITH_FAILURE
Definition: unit_test_map.c:44
#define FR_DICTIONARY_FILE
Definition: conf.h:7
#define FR_DICTIONARY_INTERNAL_DIR
Definition: conf.h:8
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition: strerror.c:733
#define fr_strerror_const_push(_msg)
Definition: strerror.h:227
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:40
#define RADIUSD_MAGIC_NUMBER
Definition: version.h:81