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: 4dc328019e1dde737efac8a93a36943c05a063af $
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: 4dc328019e1dde737efac8a93a36943c05a063af $")
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 #ifdef HAVE_GETOPT_H
35 # include <getopt.h>
36 #endif
37 
38 #include <assert.h>
39 
40 #include <freeradius-devel/server/log.h>
41 
42 #define EXIT_WITH_FAILURE \
43 do { \
44  ret = EXIT_FAILURE; \
45  goto cleanup; \
46 } while (0)
47 
48 static fr_dict_t const *dict_freeradius;
49 static fr_dict_t const *dict_radius;
50 
53  { .out = &dict_freeradius, .proto = "freeradius" },
54  { .out = &dict_radius, .proto = "radius" },
55  { NULL }
56 };
57 
58 
59 static NEVER_RETURNS void usage(char *argv[])
60 {
61  fprintf(stderr, "usage: %s [OPTS] filename ...\n", argv[0]);
62  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
63  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
64  fprintf(stderr, " -x Debugging mode.\n");
65  fprintf(stderr, " -M Show program version information.\n");
66  fprintf(stderr, " -r <receipt_file> Create the <receipt_file> as a 'success' exit.\n");
67 
68  fr_exit_now(EXIT_SUCCESS);
69 }
70 
71 static int process_file(char const *filename)
72 {
73  int rcode;
74  char const *name1, *name2;
75  CONF_SECTION *cs;
76  map_list_t list;
77  map_t *map = NULL;
78  char buffer[8192];
79 
81 
82  tmpl_rules_t parse_rules = {
83  .attr = {
85  .list_def = request_attr_request,
86  .allow_foreign = false, /* tests are in the RADIUS dictionary */
87  }
88  };
89 
90  map_list_init(&list);
91 
92  config = main_config_alloc(NULL);
93  if (!config) {
94  fprintf(stderr, "Failed allocating main config");
95  return EXIT_FAILURE;
96  }
97  config->root_cs = cf_section_alloc(config, NULL, "main", NULL);
98  cf_section_set_unlang(config->root_cs);
99 
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 
283  /*
284  * Free any autoload dictionaries
285  */
287  fr_perror("unit_test_map");
288  ret = EXIT_FAILURE;
289  }
290 
291  if (fr_dict_free(&dict, __FILE__) < 0) {
292  fr_perror("unit_test_map");
293  ret = EXIT_FAILURE;
294  }
295 
296  if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
297  fr_perror("unit_test_map");
298  ret = EXIT_FAILURE;
299  }
300 
301  /*
302  * Ensure our atexit handlers run before any other
303  * atexit handlers registered by third party libraries.
304  */
306 
307  return ret;
308 }
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:481
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
void cf_section_set_unlang(CONF_SECTION *cs)
Definition: cf_file.c:3744
int cf_file_read(CONF_SECTION *cs, char const *filename)
Definition: cf_file.c:3415
int cf_section_pass2(CONF_SECTION *cs)
Definition: cf_file.c:755
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
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:1028
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1185
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1171
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_log_perr(_cf, _fmt,...)
Definition: cf_util.h:296
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:140
#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:1207
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:1242
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition: debug.h:228
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:234
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:850
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:4024
#define fr_dict_autoload(_to_load)
Definition: dict.h:847
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:4392
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
Definition: file.c:367
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:323
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:1014
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
Definition: map.c:2295
talloc_free(reap)
int fr_debug_lvl
Definition: log.c:43
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
Definition: main_config.c:843
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
Definition: main_config.c:1003
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:470
static const conf_parser_t config[]
Definition: base.c:183
static TALLOC_CTX * autofree
Definition: radclient-ng.c:107
static bool cleanup
Definition: radsniff.c:60
fr_dict_attr_t const * request_attr_request
Definition: request.c:45
int request_global_init(void)
Definition: request.c:722
#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:52
static fr_dict_t const * dict_freeradius
Definition: unit_test_map.c:48
static int process_file(char const *filename)
Definition: unit_test_map.c:71
static fr_dict_t const * dict_radius
Definition: unit_test_map.c:49
static NEVER_RETURNS void usage(char *argv[])
Definition: unit_test_map.c:59
#define EXIT_WITH_FAILURE
Definition: unit_test_map.c:42
#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