The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
cron.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more crons.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 786073cf8c8fdc98667a68ed1c356acd9afaf890 $
19 * @file proto_cron.c
20 * @brief CRON master protocol handler.
21 *
22 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
23 */
24#include <freeradius-devel/server/base.h>
25#include <freeradius-devel/io/listen.h>
26#include <freeradius-devel/unlang/base.h>
27#include <freeradius-devel/util/debug.h>
28#include "proto_cron.h"
29
30extern fr_app_t proto_cron;
31static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
32static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
33
34static conf_parser_t const limit_config[] = {
35 /*
36 * For performance tweaking. NOT for normal humans.
37 */
38 { FR_CONF_OFFSET("max_packet_size", proto_cron_t, max_packet_size) } ,
39 { FR_CONF_OFFSET("num_messages", proto_cron_t, num_messages) } ,
40
42};
43
44/** How to parse a CRON listen section
45 *
46 */
61
62static fr_dict_t const *dict_cron;
63
66 { .out = &dict_cron, .proto = "freeradius" },
67 { NULL }
68};
69
70/** Translates the packet-type into a submodule name
71 *
72 * @param[in] ctx to allocate data in (instance of proto_cron).
73 * @param[out] out Where to write a module_instance_t containing the module handle and instance.
74 * @param[in] parent Base structure address.
75 * @param[in] ci #CONF_PAIR specifying the name of the type module.
76 * @param[in] rule unused.
77 * @return
78 * - 0 on success.
79 * - -1 on failure.
80 */
81static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
82{
83 proto_cron_t *inst = talloc_get_type_abort(parent, proto_cron_t);
84 fr_dict_enum_t const *type_enum;
85 CONF_PAIR *cp = cf_item_to_pair(ci);
86 char const *value = cf_pair_value(cp);
87
88 *((char const **) out) = value;
89
90 inst->dict = virtual_server_namespace_by_ci(ci);
91 if (!inst->dict) {
92 cf_log_err(ci, "Please define 'namespace' in this virtual server");
93 return -1;
94 }
95
96 inst->attr_packet_type = fr_dict_attr_by_name(NULL, fr_dict_root(inst->dict), "Packet-Type");
97 if (!inst->attr_packet_type) {
98 cf_log_err(ci, "Failed to find 'Packet-Type' attribute");
99 return -1;
100 }
101
102 if (!value) {
103 cf_log_err(ci, "No value given for 'type'");
104 return -1;
105 }
106
107 type_enum = fr_dict_enum_by_name(inst->attr_packet_type, value, -1);
108 if (!type_enum) {
109 cf_log_err(ci, "Invalid type \"%s\"", value);
110 return -1;
111 }
112
113 inst->code = type_enum->value->vb_uint32;
114 return 0;
115}
116
117/*
118 * Parse a basic field with sanity checks.
119 *
120 * Note that we don't (yet) convert this into an internal data
121 * structure. Instead, we're just checking if the basic format
122 * is OK.
123 */
124static int parse_field(CONF_ITEM *ci, char const **start, char const *name, unsigned int min, unsigned int max)
125{
126 char const *p;
127 char *end = NULL;
128 unsigned int num, last = 0;
129 bool last_is_set = false;
130 bool wildcard = false;
131
132 p = *start;
134
135 if (!*p) {
136 cf_log_err(ci, "Missing field for %s", name);
137 return -1;
138 }
139
140 /*
141 * See 'man 5 crontab' for the format.
142 */
143 while (p) {
144 /*
145 * Allow wildcards, but only once.
146 */
147 if (*p == '*') {
148 if (wildcard) {
149 cf_log_err(ci, "Cannot use two wildcards for %s at %s", name, p);
150 return -1;
151 }
152
153 end = UNCONST(char *, p) + 1;
154 wildcard = true;
155 goto check_step;
156 }
157
158 /*
159 * If there's already a "*", we can't have another one.
160 */
161 if (wildcard) {
162 cf_log_err(ci, "Cannot use wildcard and numbers for %s at %s", name, p);
163 return -1;
164 }
165
166 /*
167 * If it's not a wildcard, it MUST be a number,
168 * which is between min and max.
169 */
170 num = strtoul(p, &end, 10);
171 if ((num < min) || (num > max)) {
172 cf_log_err(ci, "Number is invalid or out of bounds (%d..%d) for %s at %s",
173 min, max, name, p);
174 return -1;
175 }
176
177 /*
178 * Don't allow the same number to be specified
179 * multiple times.
180 */
181 if (!last_is_set) {
182 last_is_set = true;
183
184 } else if (num <= last) {
185 cf_log_err(ci, "Number overlaps with previous value of %u, for %s at %s",
186 last, name, p);
187 return -1;
188 }
189 last = num;
190
191 /*
192 * Ranges are allowed, with potential steps
193 */
194 if (*end == '-') {
195 unsigned int next;
196
197 p = end + 1;
198 next = strtoul(p, &end, 10);
199 if (next <= num) {
200 cf_log_err(ci, "End of range number overlaps with previous value of %u, for %s at %s",
201 num, name, p);
202 return -1;
203 }
204
205 if (next > max) {
206 cf_log_err(ci, "End of range number is invalid or out of bounds (%d..%d) for %s at %s",
207 min, max, name, p);
208 return -1;
209 }
210
211 last = next;
212
213 check_step:
214 /*
215 * Allow /N
216 */
217 if (*end == '/') {
218 p = end + 1;
219
220 num = strtoul(p, &end, 10);
221 if (num > 65535) {
222 cf_log_err(ci, "Failed parsing step value for %s at %s", name, p);
223 return -1;
224 }
225 }
226 } /* end of range specifier */
227
228 /*
229 * We can specify multiple fields, separated by a comma.
230 */
231 if (*end == ',') {
232 p = end + 1;
233 continue;
234 }
235
236 /*
237 * EOS or space is end of field.
238 */
239 if (!(!*end || isspace((uint8_t) *end))) {
240 cf_log_err(ci, "Unexpected text for %s at %s", name, end);
241 return -1;
242 }
243 }
244
245 *start = end;
246 return 0;
247}
248
249/*
250 * Special names, including our own extensions.
251 */
253 { L("annually"), "0 0 1 1 *" },
254 { L("daily"), "0 0 * * *" },
255 { L("hourly"), "0 * * * *" },
256 { L("midnight"), "0 0 * * *" },
257 { L("monthly"), "0 0 1 * *" },
258 { L("reboot"), "+" },
259 { L("shutdown"), "-" },
260 { L("startup"), "+" },
261 { L("weekly"), "0 0 * * 0" },
262 { L("yearly"), "0 0 1 1 *" },
263};
265
266/** Checks the syntax of a cron job
267 *
268 * @param[in] ctx to allocate data in (instance of proto_cron).
269 * @param[out] out Where to write a module_instance_t containing the module handle and instance.
270 * @param[in] parent Base structure address.
271 * @param[in] ci #CONF_PAIR specifying the name of the type module.
272 * @param[in] rule unused.
273 * @return
274 * - 0 on success.
275 * - -1 on failure.
276 *
277 * https://github.com/staticlibs/ccronexpr/blob/master/ccronexpr.c
278 */
279static int time_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
280{
281// proto_cron_t *inst = talloc_get_type_abort(parent, proto_cron_t);
282 CONF_PAIR *cp = cf_item_to_pair(ci);
283 char const *value = cf_pair_value(cp);
284 char const *p;
285
286 p = value;
287
288 /*
289 * Check for special names.
290 */
291 if (*p == '@') {
292 p = fr_table_value_by_str(time_names, p + 1, NULL);
293 if (!p) {
294 cf_log_err(ci, "Invalid time name '%s'", value);
295 return -1;
296 }
297
298 /*
299 * Over-write the special names with standard
300 * ones, so that the rest of the parser is simpler.
301 */
302 *((char const **) out) = p;
303 return 0;
304 }
305
306 *((char const **) out) = value;
307
308 if (parse_field(ci, &p, "minute", 0, 59) < 0) return -1;
309 if (parse_field(ci, &p, "hour", 0, 59) < 0) return -1;
310 if (parse_field(ci, &p, "day of month", 1, 31) < 0) return -1;
311 if (parse_field(ci, &p, "month", 1,12) < 0) return -1;
312 if (parse_field(ci, &p, "day of week", 0, 6) < 0) return -1;
313
315
316 if (*p) {
317 cf_log_err(ci, "Unexpected text after cron time specification");
318 return -1;
319 }
320
321 return 0;
322}
323
324
325/** Open listen sockets/connect to external event source
326 *
327 * @param[in] instance Ctx data for this application.
328 * @param[in] sc to add our file descriptor to.
329 * @param[in] conf Listen section parsed to give us instance.
330 * @return
331 * - 0 on success.
332 * - -1 on failure.
333 */
334static int mod_open(void *instance, fr_schedule_t *sc, UNUSED CONF_SECTION *conf)
335{
336 proto_cron_t *inst = talloc_get_type_abort(instance, proto_cron_t);
337 fr_listen_t *li;
338
339 /*
340 * Build the #fr_listen_t. This describes the complete
341 * path, data takes from the socket to the decoder and
342 * back again.
343 */
344 li = talloc_zero(inst, fr_listen_t);
345 talloc_set_destructor(li, fr_io_listen_free);
346
347 /*
348 * Set to the cron_app_io, which gets the network && event list.
349 */
350// li->app_io = inst->app_io;
351 li->thread_instance = talloc_zero_array(NULL, uint8_t, sizeof(proto_cron_thread_t));
352 talloc_set_type(li->thread_instance, proto_cron_thread_t);
353 li->app_io_instance = NULL;
354
355 li->app = &proto_cron;
356 li->app_instance = instance;
357 li->server_cs = inst->server_cs;
358
359 /*
360 * Set configurable parameters for message ring buffer.
361 */
362 li->default_message_size = inst->max_packet_size;
363 li->num_messages = inst->num_messages;
364
365 li->name = "cron";
366 li->fd = -1; /* not a real FD! */
367
368 /*
369 * Watch the directory for changes.
370 */
371 if (!fr_schedule_listen_add(sc, li)) {
372 talloc_free(li);
373 return -1;
374 }
375
376 DEBUG(951, 951, "Listening on %s bound to virtual server %s",
378
379 inst->listen = li; /* Probably won't need it, but doesn't hurt */
380 inst->sc = sc;
381
382 return 0;
383}
384
385/** Instantiate the application
386 *
387 * Instantiate I/O and type submodules.
388 *
389 * @param[in] instance Ctx data for this application.
390 * @param[in] conf Listen section parsed to give us instance.
391 * @return
392 * - 0 on success.
393 * - -1 on failure.
394 */
395static int mod_instantiate(void *instance, CONF_SECTION *conf)
396{
397 proto_cron_t *inst = talloc_get_type_abort(instance, proto_cron_t);
398 FILE *fp;
399 bool done;
400
401 /*
402 * The listener is inside of a virtual server.
403 */
404 inst->server_cs = cf_item_to_section(cf_parent(conf));
405 inst->cs = conf;
406 inst->self = &proto_cron;
407
408 virtual_server_dict_set(inst->server_cs, inst->dict, false);
409
410 FR_INTEGER_BOUND_CHECK("num_messages", inst->num_messages, >=, 32);
411 FR_INTEGER_BOUND_CHECK("num_messages", inst->num_messages, <=, 65535);
412
413 FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, >=, 1024);
414 FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, <=, 65535);
415
416 if (!inst->priority) inst->priority = PRIORITY_NORMAL;
417
418 fp = fopen(inst->filename, "r");
419 if (!fp) {
420 cf_log_err(conf, "Failed opening %s - %s", inst->filename, fr_syserror(errno));
421 return -1;
422 }
423
424 if (fr_pair_list_afrom_file(inst, inst->dict, &inst->vps, fp, &done) < 0) {
425 fclose(fp);
426 cf_log_err(conf, "Failed reading %s - %s", inst->filename, fr_strerror());
427 return -1;
428 }
429 fclose(fp);
430
431 if (!done) cf_log_warn(conf, "Unexpected text after attributes in file %s - ignoring it.", inst->filename);
432
433 return 0;
434}
435
437 .magic = RLM_MODULE_INIT,
438 .name = "cron",
439 .config = proto_cron_config,
440 .inst_size = sizeof(proto_cron_t),
441
443 .open = mod_open,
444};
Describes a new application (protocol)
Definition application.h:71
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:596
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:502
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:323
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:418
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition cf_parse.h:424
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:433
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:412
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1185
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:684
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:664
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1594
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_parent(_cf)
Definition cf_util.h:101
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:290
#define PRIORITY_NORMAL
Definition channel.h:151
static fr_dict_t const * dict_cron
Definition cron.c:62
fr_app_t proto_cron
Definition cron.c:436
static conf_parser_t const limit_config[]
Definition cron.c:34
static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int mod_instantiate(void *instance, CONF_SECTION *conf)
Instantiate the application.
Definition cron.c:395
static size_t time_names_len
Definition cron.c:264
static int parse_field(CONF_ITEM *ci, char const **start, char const *name, unsigned int min, unsigned int max)
Definition cron.c:124
static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static conf_parser_t const proto_cron_config[]
How to parse a CRON listen section.
Definition cron.c:47
static int mod_open(void *instance, fr_schedule_t *sc, UNUSED CONF_SECTION *conf)
Open listen sockets/connect to external event source.
Definition cron.c:334
static fr_table_ptr_sorted_t time_names[]
Definition cron.c:252
fr_dict_autoload_t proto_cron_dict[]
Definition cron.c:65
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3395
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
Test enumeration values.
Definition dict_test.h:92
size_t num_messages
for the message ring buffer
Definition listen.h:52
char const * name
printable name for this socket - set by open
Definition listen.h:29
void const * app_instance
Definition listen.h:38
size_t default_message_size
copied from app_io, but may be changed
Definition listen.h:51
fr_app_t const * app
Definition listen.h:37
void const * app_io_instance
I/O path configuration context.
Definition listen.h:32
int fr_io_listen_free(fr_listen_t *li)
Definition master.c:2917
CONF_SECTION * server_cs
CONF_SECTION of the server.
Definition listen.h:40
void * thread_instance
thread / socket context
Definition listen.h:33
int fd
file descriptor for this socket - set by open
Definition listen.h:28
talloc_free(reap)
@ FR_TYPE_VOID
User data.
unsigned char uint8_t
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition misc.h:59
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
Read valuepairs from the fp up to End-Of-File.
Cron master protocol handler.
static bool done
Definition radclient.c:80
static rs_t * conf
Definition radsniff.c:53
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
Definition schedule.c:881
The scheduler.
Definition schedule.c:125
static const uchar sc[16]
Definition smbdes.c:115
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
An element in a lexicographically sorted array of name to ptr mappings.
Definition table.h:65
static fr_slen_t parent
Definition pair.h:851
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
static size_t char ** out
Definition value.h:997