2 * util.c Various utility functions.
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.
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.
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
20 * Copyright 2000,2006 The FreeRADIUS server project
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/rad_assert.h>
34 * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
35 * sa_flags, which causes grief if signal() is called in the
36 * handler before the cause of the signal has been cleared.
37 * (Infinite recursion).
39 * The same problem appears on HPUX, so we avoid it, if we can.
41 * Using sigaction() to reset the signal handler fixes the problem,
42 * so where available, we prefer that solution.
45 void (*reset_signal(int signo, void (*func)(int)))(int)
48 struct sigaction act, oact;
50 memset(&act, 0, sizeof(act));
51 act.sa_handler = func;
52 sigemptyset(&act.sa_mask);
54 #ifdef SA_INTERRUPT /* SunOS */
55 act.sa_flags |= SA_INTERRUPT;
57 if (sigaction(signo, &act, &oact) < 0)
59 return oact.sa_handler;
63 * re-set by calling the 'signal' function, which
64 * may cause infinite recursion and core dumps due to
67 * However, the system is too dumb to implement sigaction(),
68 * so we don't have a choice.
77 * Per-request data, added by modules...
79 struct request_data_t {
89 * Add opaque data (with a "free" function) to a REQUEST.
91 * The unique ptr is meant to be a module configuration,
92 * and the unique integer allows the caller to have multiple
93 * opaque data associated with a REQUEST.
95 int request_data_add(REQUEST *request,
96 void *unique_ptr, int unique_int,
97 void *opaque, bool free_opaque)
99 request_data_t *this, **last, *next;
102 * Some simple sanity checks.
104 if (!request || !opaque) return -1;
107 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
108 if (((*last)->unique_ptr == unique_ptr) &&
109 ((*last)->unique_int == unique_int)) {
115 * If caller requires custom behaviour on free
116 * they must set a destructor.
118 if (this->opaque && this->free_opaque) {
119 talloc_free(this->opaque);
121 break; /* replace the existing entry */
125 if (!this) this = talloc_zero(request, request_data_t);
128 this->unique_ptr = unique_ptr;
129 this->unique_int = unique_int;
130 this->opaque = opaque;
132 this->free_opaque = free_opaque;
142 * Get opaque data from a request.
144 void *request_data_get(REQUEST *request,
145 void *unique_ptr, int unique_int)
147 request_data_t **last;
149 if (!request) return NULL;
151 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
152 if (((*last)->unique_ptr == unique_ptr) &&
153 ((*last)->unique_int == unique_int)) {
154 request_data_t *this = *last;
155 void *ptr = this->opaque;
158 * Remove the entry from the list, and free it.
162 return ptr; /* don't free it, the caller does that */
166 return NULL; /* wasn't found, too bad... */
171 * Get opaque data from a request without removing it.
173 void *request_data_reference(REQUEST *request,
174 void *unique_ptr, int unique_int)
176 request_data_t **last;
178 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
179 if (((*last)->unique_ptr == unique_ptr) &&
180 ((*last)->unique_int == unique_int)) {
181 request_data_t *this = *last;
182 void *ptr = this->opaque;
188 return NULL; /* wasn't found, too bad... */
192 * Create possibly many directories.
194 * Note that the input directory name is NOT a constant!
195 * This is so that IF an error is returned, the 'directory' ptr
196 * points to the name of the file which caused the error.
198 int rad_mkdir(char *directory, mode_t mode)
204 * Try to make the directory. If it exists, chmod it.
205 * If a path doesn't exist, that's OK. Otherwise
206 * return with an error.
208 rcode = mkdir(directory, mode & 0777);
210 if (errno == EEXIST) {
211 return chmod(directory, mode);
214 if (errno != ENOENT) {
219 * A component in the directory path doesn't
220 * exist. Look for the LAST directory name. Try
221 * to create that. If there's an error, we leave
222 * the directory path as the one at which the
225 p = strrchr(directory, FR_DIR_SEP);
226 if (!p || (p == directory)) return -1;
229 rcode = rad_mkdir(directory, mode);
230 if (rcode < 0) return rcode;
233 * Reset the directory path, and try again to
234 * make the directory.
237 rcode = mkdir(directory, mode & 0777);
238 if (rcode < 0) return rcode;
239 } /* else we successfully created the directory */
241 return chmod(directory, mode);
246 * Allocate memory, or exit.
248 * This call ALWAYS succeeds!
250 void *rad_malloc(size_t size)
252 void *ptr = malloc(size);
263 void rad_const_free(void const *ptr)
268 memcpy(&tmp, &ptr, sizeof(tmp));
274 * Logs an error message and aborts the program
278 void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
280 ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
286 * Free a REQUEST struct.
288 static int _request_free(REQUEST *request)
290 rad_assert(!request->in_request_hash);
292 rad_assert(!request->in_proxy_hash);
294 rad_assert(!request->ev);
298 request->coa->parent = NULL;
301 if (request->parent && (request->parent->coa == request)) {
302 request->parent->coa = NULL;
307 request->magic = 0x01020304; /* set the request to be nonsense */
309 request->client = NULL;
311 request->home_server = NULL;
318 * Create a new REQUEST data structure.
320 REQUEST *request_alloc(TALLOC_CTX *ctx)
324 request = talloc_zero(ctx, REQUEST);
325 talloc_set_destructor(request, _request_free);
327 request->magic = REQUEST_MAGIC;
330 request->proxy = NULL;
332 request->reply = NULL;
334 request->proxy_reply = NULL;
336 request->config_items = NULL;
337 request->username = NULL;
338 request->password = NULL;
339 request->timestamp = time(NULL);
340 request->log.lvl = debug_flag; /* Default to global debug level */
342 request->module = "";
343 request->component = "<core>";
344 request->log.func = vradlog_request;
351 * Create a new REQUEST, based on an old one.
353 * This function allows modules to inject fake requests
354 * into the server, for tunneled protocols like TTLS & PEAP.
356 REQUEST *request_alloc_fake(REQUEST *request)
360 fake = request_alloc(request);
362 fake->number = request->number;
363 #ifdef HAVE_PTHREAD_H
364 fake->child_pid = request->child_pid;
366 fake->parent = request;
367 fake->root = request->root;
368 fake->client = request->client;
371 * For new server support.
373 * FIXME: Key instead off of a "virtual server" data structure.
375 * FIXME: Permit different servers for inner && outer sessions?
377 fake->server = request->server;
379 fake->packet = rad_alloc(fake, 1);
385 fake->reply = rad_alloc(fake, 0);
391 fake->master_state = REQUEST_ACTIVE;
392 fake->child_state = REQUEST_RUNNING;
395 * Fill in the fake request.
397 fake->packet->sockfd = -1;
398 fake->packet->src_ipaddr = request->packet->src_ipaddr;
399 fake->packet->src_port = request->packet->src_port;
400 fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
401 fake->packet->dst_port = 0;
404 * This isn't STRICTLY required, as the fake request MUST NEVER
405 * be put into the request list. However, it's still reasonable
408 fake->packet->id = fake->number & 0xff;
409 fake->packet->code = request->packet->code;
410 fake->timestamp = request->timestamp;
411 fake->packet->timestamp = request->packet->timestamp;
414 * Required for new identity support
416 fake->listener = request->listener;
419 * Fill in the fake reply, based on the fake request.
421 fake->reply->sockfd = fake->packet->sockfd;
422 fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
423 fake->reply->src_port = fake->packet->dst_port;
424 fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
425 fake->reply->dst_port = fake->packet->src_port;
426 fake->reply->id = fake->packet->id;
427 fake->reply->code = 0; /* UNKNOWN code */
430 * Copy debug information.
432 memcpy(&(fake->log), &(request->log), sizeof(fake->log));
438 REQUEST *request_alloc_coa(REQUEST *request)
440 if (!request || request->coa) return NULL;
443 * Originate CoA requests only when necessary.
445 if ((request->packet->code != PW_CODE_ACCESS_REQUEST) &&
446 (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
448 request->coa = request_alloc_fake(request);
449 if (!request->coa) return NULL;
451 request->coa->packet->code = 0; /* unknown, as of yet */
452 request->coa->child_state = REQUEST_RUNNING;
453 request->coa->proxy = rad_alloc(request->coa, 0);
454 if (!request->coa->proxy) {
455 TALLOC_FREE(request->coa);
464 * Copy a quoted string.
466 int rad_copy_string(char *to, char const *from)
478 } while (*from && (*from != quote));
480 if (*from != quote) return -1; /* not properly quoted */
490 * Copy a quoted string but without the quotes. The length
491 * returned is the number of chars written; the number of
492 * characters consumed is 2 more than this.
494 int rad_copy_string_bare(char *to, char const *from)
500 while (*from && (*from != quote)) {
509 if (*from != quote) return -1; /* not properly quoted */
520 int rad_copy_variable(char *to, char const *from)
532 sublen = rad_copy_string(to, from);
533 if (sublen < 0) return sublen;
539 case '}': /* end of variable expansion */
543 return length; /* proper end of variable */
551 case '%': /* start of variable expansion */
552 if (from[1] == '{') {
556 sublen = rad_copy_variable(to, from);
557 if (sublen < 0) return sublen;
562 } /* else FIXME: catch %%{ ?*/
570 } /* loop over the input string */
573 * We ended the string before a trailing '}'
583 uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
587 if (*then != now->tv_sec) {
594 * Bootstrap PPS by looking at a percentage of
595 * the previous PPS. This lets us take a moving
596 * count, without doing a moving average. If
597 * we're a fraction "f" (0..1) into the current
598 * second, we can get a good guess for PPS by
601 * PPS = pps_now + pps_old * (1 - f)
603 * It's an instantaneous measurement, rather than
604 * a moving average. This will hopefully let it
605 * respond better to sudden spikes.
607 * Doing the calculations by thousands allows us
608 * to not overflow 2^32, AND to not underflow
609 * when we divide by USEC.
611 pps = USEC - now->tv_usec; /* useconds left in previous second */
612 pps /= 1000; /* scale to milliseconds */
613 pps *= *past; /* multiply by past count to get fraction */
614 pps /= 1000; /* scale to usec again */
615 pps += *present; /* add in current count */
620 /** Split string into words and expand each one
622 * @param request Current request.
623 * @param cmd string to split.
624 * @param max_argc the maximum number of arguments to split into.
625 * @param argv Where to write the pointers into argv_buf.
626 * @param can_fail If false, stop processing if any of the xlat expansions fail.
627 * @param argv_buflen size of argv_buf.
628 * @param argv_buf temporary buffer we used to mangle/expand cmd.
629 * Pointers to offsets of this buffer will be written to argv.
630 * @return argc or -1 on failure.
633 int rad_expand_xlat(REQUEST *request, char const *cmd,
634 int max_argc, char *argv[], bool can_fail,
635 size_t argv_buflen, char *argv_buf)
643 if (strlen(cmd) > (argv_buflen - 1)) {
644 ERROR("rad_expand_xlat: Command line is too long");
649 * Check for bad escapes.
651 if (cmd[strlen(cmd) - 1] == '\\') {
652 ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
656 strlcpy(argv_buf, cmd, argv_buflen);
659 * Split the string into argv's BEFORE doing radius_xlat...
670 if ((*from == ' ') || (*from == '\t')) {
678 if (argc >= (max_argc - 1)) break;
681 * Copy the argv over to our buffer.
683 while (*from && (*from != ' ') && (*from != '\t')) {
684 if (to >= argv_buf + argv_buflen - 1) {
685 ERROR("rad_expand_xlat: Ran out of space in command line");
692 length = rad_copy_string_bare(to, from);
694 ERROR("rad_expand_xlat: Invalid string passed as argument");
702 if (from[1] == '{') {
705 length = rad_copy_variable(to, from);
707 ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
712 } else { /* FIXME: catch %%{ ? */
718 if (from[1] == ' ') from++;
724 } /* end of string, or found a space */
726 *(to++) = '\0'; /* terminate the string */
730 * We have to have SOMETHING, at least.
733 ERROR("rad_expand_xlat: Empty command line");
738 * Expand each string, as appropriate.
740 left = argv_buf + argv_buflen - to;
741 for (i = 0; i < argc; i++) {
745 * Don't touch argv's which won't be translated.
747 if (strchr(argv[i], '%') == NULL) continue;
749 if (!request) continue;
751 sublen = radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
755 * Fail to be backwards compatible.
757 * It's yucky, but it won't break anything,
758 * and it won't cause security problems.
762 ERROR("rad_expand_xlat: xlat failed");
774 ERROR("rad_expand_xlat: Ran out of space while expanding arguments");
783 const FR_NAME_NUMBER pair_lists[] = {
784 { "request", PAIR_LIST_REQUEST },
785 { "reply", PAIR_LIST_REPLY },
786 { "control", PAIR_LIST_CONTROL }, /* New name should have priority */
787 { "config", PAIR_LIST_CONTROL },
789 { "proxy-request", PAIR_LIST_PROXY_REQUEST },
790 { "proxy-reply", PAIR_LIST_PROXY_REPLY },
793 { "coa", PAIR_LIST_COA },
794 { "coa-reply", PAIR_LIST_COA_REPLY },
795 { "disconnect", PAIR_LIST_DM },
796 { "disconnect-reply", PAIR_LIST_DM_REPLY },
801 const FR_NAME_NUMBER request_refs[] = {
802 { "outer", REQUEST_OUTER },
803 { "current", REQUEST_CURRENT },
804 { "parent", REQUEST_PARENT },
809 /** Resolve attribute name to a list.
811 * Check the name string for qualifiers that specify a list and return
812 * an pair_lists_t value for that list. This value may be passed to
813 * radius_list, along with the current request, to get a pointer to the
814 * actual list in the request.
816 * If qualifiers were consumed, write a new pointer into name to the
817 * char after the last qualifier to be consumed.
819 * radius_list_name should be called before passing a name string that
820 * may contain qualifiers to dict_attrbyname.
822 * @see dict_attrbyname
824 * @param[in,out] name of attribute.
825 * @param[in] default_list the list to return if no qualifiers were found.
826 * @return PAIR_LIST_UNKOWN if qualifiers couldn't be resolved to a list.
828 pair_lists_t radius_list_name(char const **name, pair_lists_t default_list)
830 char const *p = *name;
834 /* This should never be a NULL pointer or zero length string */
835 rad_assert(name && *name);
838 * Unfortunately, ':' isn't a definitive separator for
839 * the list name. We may have numeric tags, too.
844 * Check for tagged attributes. They have
845 * "name:tag", where tag is a decimal number.
846 * Valid tags are invalid attributes, so that's
849 * Also allow "name:tag[#]" as a tag.
851 * However, "request:" is allowed, too, and
852 * shouldn't be interpreted as a tag.
854 * We do this check first rather than just
855 * looking up the request name, because this
856 * check is cheap, and looking up the request
859 if (isdigit((int) q[1])) {
860 char const *d = q + 1;
862 while (isdigit((int) *d)) {
867 * Return the DEFAULT list as supplied by
868 * the caller. This is usually
871 if (!*d || (*d == '[')) {
877 * If the first part is a list name, then treat
878 * it as a list. This means that we CANNOT have
879 * an attribute which is named "request",
880 * "reply", etc. Allowing a tagged attribute
881 * "request:3" would just be insane.
883 output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
884 if (output != PAIR_LIST_UNKNOWN) {
885 *name = (q + 1); /* Consume the list and delimiter */
890 * It's not a known list, say so.
892 return PAIR_LIST_UNKNOWN;
896 * The input string may be just a list name,
897 * e.g. "request". Check for that.
900 output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
901 if (output != PAIR_LIST_UNKNOWN) {
907 * It's just an attribute name. Return the default list
908 * as supplied by the caller.
914 /** Resolve attribute name to a request.
916 * Check the name string for qualifiers that reference a parent request and
917 * write the pointer to this request to 'request'.
919 * If qualifiers were consumed, write a new pointer into name to the
920 * char after the last qualifier to be consumed.
922 * radius_ref_request should be called before radius_list_name.
924 * @see radius_list_name
925 * @param[in,out] name of attribute.
926 * @param[in] def default request ref to return if no request qualifier is present.
927 * @return one of the REQUEST_* definitions or REQUEST_UNKOWN
929 request_refs_t radius_request_name(char const **name, request_refs_t def)
934 p = strchr(*name, '.');
940 * We may get passed "127.0.0.1".
942 request = fr_substr2int(request_refs, *name, REQUEST_UNKNOWN,
946 * If we get a valid name, skip it.
948 if (request != REQUEST_UNKNOWN) {
954 * Otherwise leave it alone, and return the caller's
960 /** Resolve request to a request.
962 * Resolve name to a current request.
965 * @param[in,out] context Base context to use, and to write the result back to.
966 * @param[in] name (request) to resolve to.
967 * @return 0 if request is valid in this context, else -1.
969 int radius_request(REQUEST **context, request_refs_t name)
971 REQUEST *request = *context;
974 case REQUEST_CURRENT:
977 case REQUEST_PARENT: /* for future use in request chaining */
979 if (!request->parent) {
982 *context = request->parent;
985 case REQUEST_UNKNOWN:
994 /** Adds subcapture values to request data
996 * Allows use of %{n} expansions.
998 * @param request Current request.
999 * @param compare Result returned by regexec.
1000 * @param value The original value.
1001 * @param rxmatch Pointers into value.
1003 void rad_regcapture(REQUEST *request, int compare, char const *value, regmatch_t rxmatch[])
1009 if (compare == REG_NOMATCH) {
1014 * Add new %{0}, %{1}, etc.
1016 for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
1018 * Didn't match: delete old match, if it existed.
1020 if (rxmatch[i].rm_so == -1) {
1021 p = request_data_get(request, request, REQUEST_DATA_REGEX | i);
1023 RDEBUG4("%%{%i}: Clearing old value \"%s\"", i, p);
1026 RDEBUG4("%%{%i}: Was empty", i);
1032 len = rxmatch[i].rm_eo - rxmatch[i].rm_so;
1033 p = talloc_array(request, char, len + 1);
1035 ERROR("Out of memory");
1039 memcpy(p, value + rxmatch[i].rm_so, len);
1042 RDEBUG4("%%{%i}: Inserting new value \"%s\"", i, p);
1044 * Copy substring, and add it to
1047 * Note that we don't check
1048 * for out of memory, which is
1049 * the only error we can get...
1051 request_data_add(request, request, REQUEST_DATA_REGEX | i, p, true);
1059 static void verify_packet(char const *file, int line, REQUEST *request, RADIUS_PACKET *packet)
1064 fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%u]: RADIUS_PACKET pointer was NULL", file, line);
1069 parent = talloc_parent(packet);
1070 if (parent != request) {
1071 ERROR("CONSISTENCY CHECK FAILED %s[%u]: Expected RADIUS_PACKET to be parented by %p (%s), "
1072 "but parented by %p (%s)", file, line, request, talloc_get_name(request),
1073 parent, parent ? talloc_get_name(parent) : "NULL");
1075 fr_log_talloc_report(packet);
1076 if (parent) fr_log_talloc_report(parent);
1081 VERIFY_PACKET(packet);
1083 if (!packet->vps) return;
1085 #ifdef WITH_VERIFY_PTR
1086 fr_verify_list(file, line, packet, packet->vps);
1090 * Catch horrible talloc errors.
1092 void verify_request(char const *file, int line, REQUEST *request)
1095 fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%u]: REQUEST pointer was NULL", file, line);
1100 (void) talloc_get_type_abort(request, REQUEST);
1102 #ifdef WITH_VERIFY_PTR
1103 fr_verify_list(file, line, request, request->config_items);
1106 if (request->packet) verify_packet(file, line, request, request->packet);
1107 if (request->reply) verify_packet(file, line, request, request->reply);
1109 if (request->proxy) verify_packet(file, line, request, request->proxy);
1110 if (request->proxy_reply) verify_packet(file, line, request, request->proxy_reply);
1117 (void) talloc_get_type_abort(request->coa, REQUEST);
1118 parent = talloc_parent(request->coa);
1120 rad_assert(parent == request);
1122 verify_request(file, line, request->coa);