#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
-#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
void *unique_ptr;
int unique_int;
void *opaque;
- void (*free_opaque)(void *);
+ bool free_opaque;
};
/*
*/
int request_data_add(REQUEST *request,
void *unique_ptr, int unique_int,
- void *opaque, void (*free_opaque)(void *))
+ void *opaque, bool free_opaque)
{
request_data_t *this, **last, *next;
next = this->next;
- if (this->opaque && /* free it, if necessary */
- this->free_opaque)
- this->free_opaque(this->opaque);
- break; /* replace the existing entry */
+ /*
+ * If caller requires custom behaviour on free
+ * they must set a destructor.
+ */
+ if (this->opaque && this->free_opaque) {
+ talloc_free(this->opaque);
+ }
+ break; /* replace the existing entry */
}
}
- if (!this) this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
+ if (!this) this = talloc_zero(request, request_data_t);
this->next = next;
this->unique_ptr = unique_ptr;
this->unique_int = unique_int;
this->opaque = opaque;
- this->free_opaque = free_opaque;
+ if (free_opaque) {
+ this->free_opaque = free_opaque;
+ }
*last = this;
* Remove the entry from the list, and free it.
*/
*last = this->next;
- free(this);
- return ptr; /* don't free it, the caller does that */
+ talloc_free(this);
+ return ptr; /* don't free it, the caller does that */
}
}
return NULL; /* wasn't found, too bad... */
}
-
-/*
- * Free a REQUEST struct.
- */
-void request_free(REQUEST **request_ptr)
-{
- REQUEST *request;
-
- if (!request_ptr || !*request_ptr) {
- return;
- }
-
- request = *request_ptr;
-
- rad_assert(!request->in_request_hash);
-#ifdef WITH_PROXY
- rad_assert(!request->in_proxy_hash);
-#endif
- rad_assert(!request->ev);
-
- if (request->packet)
- rad_free(&request->packet);
-
-#ifdef WITH_PROXY
- if (request->proxy)
- rad_free(&request->proxy);
-#endif
-
- if (request->reply)
- rad_free(&request->reply);
-
-#ifdef WITH_PROXY
- if (request->proxy_reply)
- rad_free(&request->proxy_reply);
-#endif
-
- if (request->config_items)
- pairfree(&request->config_items);
-
- request->username = NULL;
- request->password = NULL;
-
- if (request->data) {
- request_data_t *this, *next;
-
- for (this = request->data; this != NULL; this = next) {
- next = this->next;
- if (this->opaque && /* free it, if necessary */
- this->free_opaque)
- this->free_opaque(this->opaque);
- free(this);
- }
- request->data = NULL;
- }
-
- if (request->root &&
- (request->root->refcount > 0)) {
- request->root->refcount--;
- request->root = NULL;
- }
-
-#ifdef WITH_COA
- if (request->coa) {
- request->coa->parent = NULL;
- rad_assert(request->coa->ev == NULL);
- request_free(&request->coa);
- }
-
- if (request->parent && (request->parent->coa == request)) {
- request->parent->coa = NULL;
- }
-#endif
-
-#ifndef NDEBUG
- request->magic = 0x01020304; /* set the request to be nonsense */
-#endif
- request->client = NULL;
-#ifdef WITH_PROXY
- request->home_server = NULL;
-#endif
- talloc_free(request);
- *request_ptr = NULL;
-}
-
-/*
- * Check a filename for sanity.
- *
- * Allow only uppercase/lowercase letters, numbers, and '-_/.'
- */
-int rad_checkfilename(const char *filename)
-{
- if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
- return 0;
- }
-
- return -1;
-}
-
-/** Check if file exists
- *
- * @param filename to check.
- * @return 0 if the file does not exist, 1 if the file exists, -1 if the file
- * exists but there was an error opening it. errno value should be usable
- * for error messages.
- */
-int rad_file_exists(const char *filename)
-{
- int des;
- int ret = 1;
-
- if ((des = open(filename, O_RDONLY)) == -1) {
- if (errno == ENOENT) {
- ret = 0;
- } else {
- ret = -1;
- }
- } else {
- close(des);
- }
-
- return ret;
-}
-
/*
* Create possibly many directories.
*
{
int rcode;
char *p;
- struct stat st;
/*
- * If the directory exists, don't do anything.
+ * Try to make the directory. If it exists, chmod it.
+ * If a path doesn't exist, that's OK. Otherwise
+ * return with an error.
*/
- if (stat(directory, &st) == 0) {
- return 0;
- }
+ rcode = mkdir(directory, mode & 0777);
+ if (rcode < 0) {
+ if (errno == EEXIST) {
+ return chmod(directory, mode);
+ }
- /*
- * Look for the LAST directory name. Try to create that,
- * failing on any error.
- */
- p = strrchr(directory, FR_DIR_SEP);
- if (p != NULL) {
- *p = '\0';
- rcode = rad_mkdir(directory, mode);
+ if (errno != ENOENT) {
+ return rcode;
+ }
/*
- * On error, we leave the directory name as the
- * one which caused the error.
+ * A component in the directory path doesn't
+ * exist. Look for the LAST directory name. Try
+ * to create that. If there's an error, we leave
+ * the directory path as the one at which the
+ * error occured.
*/
- if (rcode < 0) {
- if (errno == EEXIST) return 0;
- return rcode;
- }
+ p = strrchr(directory, FR_DIR_SEP);
+ if (!p || (p == directory)) return -1;
+
+ *p = '\0';
+ rcode = rad_mkdir(directory, mode);
+ if (rcode < 0) return rcode;
/*
- * Reset the directory delimiter, and go ask
- * the system to make the directory.
+ * Reset the directory path, and try again to
+ * make the directory.
*/
*p = FR_DIR_SEP;
- } else {
- return 0;
- }
+ rcode = mkdir(directory, mode & 0777);
+ if (rcode < 0) return rcode;
+ } /* else we successfully created the directory */
- /*
- * Having done everything successfully, we do the
- * system call to actually go create the directory.
- */
- rcode = mkdir(directory, mode & 0777);
- if (rcode < 0) {
- return rcode;
- }
-
- /*
- * Set things like sticky bits that aren't supported by
- * mkdir.
- */
- if (mode & ~0777) {
- rcode = chmod(directory, mode);
- }
-
- return rcode;
+ return chmod(directory, mode);
}
void *ptr = malloc(size);
if (ptr == NULL) {
- DEBUGE("no memory");
- exit(1);
+ ERROR("no memory");
+ fr_exit(1);
}
return ptr;
}
-void *rad_calloc(size_t size)
-{
- void *ptr = rad_malloc(size);
- memset(ptr, 0, size);
- return ptr;
-}
-
-void rad_const_free(const void *ptr)
+void rad_const_free(void const *ptr)
{
void *tmp;
if (!ptr) return;
/*
- * Signature for free is dumb, and raises errors when we try
- * to free const ptrs.
+ * Logs an error message and aborts the program
+ *
*/
-void rad_cfree(const void *ptr)
-{
- void *tmp;
- if (!ptr) return;
- memcpy(&tmp, &ptr, sizeof(tmp));
- free(tmp);
+void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
+{
+ ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
+ fr_fault(SIGABRT);
+ fr_exit_now(1);
}
/*
- * Logs an error message and aborts the program
- *
+ * Free a REQUEST struct.
*/
-
-void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
- const char *expr)
+static int _request_free(REQUEST *request)
{
- DEBUGE("ASSERT FAILED %s[%u]: %s", file, line, expr);
- abort();
-}
+ rad_assert(!request->in_request_hash);
+#ifdef WITH_PROXY
+ rad_assert(!request->in_proxy_hash);
+#endif
+ rad_assert(!request->ev);
+
+#ifdef WITH_COA
+ if (request->coa) {
+ request->coa->parent = NULL;
+ }
+ if (request->parent && (request->parent->coa == request)) {
+ request->parent->coa = NULL;
+ }
+#endif
+
+#ifndef NDEBUG
+ request->magic = 0x01020304; /* set the request to be nonsense */
+#endif
+ request->client = NULL;
+#ifdef WITH_PROXY
+ request->home_server = NULL;
+#endif
+
+ return 0;
+}
/*
* Create a new REQUEST data structure.
*/
-REQUEST *request_alloc(void)
+REQUEST *request_alloc(TALLOC_CTX *ctx)
{
REQUEST *request;
- request = talloc_zero(NULL, REQUEST);
+ request = talloc_zero(ctx, REQUEST);
+ talloc_set_destructor(request, _request_free);
#ifndef NDEBUG
request->magic = REQUEST_MAGIC;
#endif
request->username = NULL;
request->password = NULL;
request->timestamp = time(NULL);
- request->options = debug_flag; /* Default to global debug level */
+ request->log.lvl = debug_flag; /* Default to global debug level */
request->module = "";
request->component = "<core>";
- if (debug_flag) request->radlog = radlog_request;
+ request->log.func = vradlog_request;
return request;
}
*/
REQUEST *request_alloc_fake(REQUEST *request)
{
- REQUEST *fake;
+ REQUEST *fake;
- fake = request_alloc();
+ fake = request_alloc(request);
- fake->number = request->number;
+ fake->number = request->number;
#ifdef HAVE_PTHREAD_H
- fake->child_pid = request->child_pid;
+ fake->child_pid = request->child_pid;
#endif
- fake->parent = request;
- fake->root = request->root;
- fake->client = request->client;
-
- /*
- * For new server support.
- *
- * FIXME: Key instead off of a "virtual server" data structure.
- *
- * FIXME: Permit different servers for inner && outer sessions?
- */
- fake->server = request->server;
-
- fake->packet = rad_alloc(request, 1);
- if (!fake->packet) {
- request_free(&fake);
- return NULL;
- }
-
- fake->reply = rad_alloc(request, 0);
- if (!fake->reply) {
- request_free(&fake);
- return NULL;
- }
-
- fake->master_state = REQUEST_ACTIVE;
- fake->child_state = REQUEST_RUNNING;
-
- /*
- * Fill in the fake request.
- */
- fake->packet->sockfd = -1;
- fake->packet->src_ipaddr = request->packet->src_ipaddr;
- fake->packet->src_port = request->packet->src_port;
- fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
- fake->packet->dst_port = 0;
-
- /*
- * This isn't STRICTLY required, as the fake request MUST NEVER
- * be put into the request list. However, it's still reasonable
- * practice.
- */
- fake->packet->id = fake->number & 0xff;
- fake->packet->code = request->packet->code;
- fake->timestamp = request->timestamp;
-
- /*
- * Required for new identity support
- */
- fake->listener = request->listener;
-
- /*
- * Fill in the fake reply, based on the fake request.
- */
- fake->reply->sockfd = fake->packet->sockfd;
- fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
- fake->reply->src_port = fake->packet->dst_port;
- fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
- fake->reply->dst_port = fake->packet->src_port;
- fake->reply->id = fake->packet->id;
- fake->reply->code = 0; /* UNKNOWN code */
-
- /*
- * Copy debug information.
- */
- fake->options = request->options;
- fake->radlog = request->radlog;
-
- return fake;
+ fake->parent = request;
+ fake->root = request->root;
+ fake->client = request->client;
+
+ /*
+ * For new server support.
+ *
+ * FIXME: Key instead off of a "virtual server" data structure.
+ *
+ * FIXME: Permit different servers for inner && outer sessions?
+ */
+ fake->server = request->server;
+
+ fake->packet = rad_alloc(fake, true);
+ if (!fake->packet) {
+ talloc_free(fake);
+ return NULL;
+ }
+
+ fake->reply = rad_alloc(fake, false);
+ if (!fake->reply) {
+ talloc_free(fake);
+ return NULL;
+ }
+
+ fake->master_state = REQUEST_ACTIVE;
+ fake->child_state = REQUEST_RUNNING;
+
+ /*
+ * Fill in the fake request.
+ */
+ fake->packet->sockfd = -1;
+ fake->packet->src_ipaddr = request->packet->src_ipaddr;
+ fake->packet->src_port = request->packet->src_port;
+ fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
+ fake->packet->dst_port = 0;
+
+ /*
+ * This isn't STRICTLY required, as the fake request MUST NEVER
+ * be put into the request list. However, it's still reasonable
+ * practice.
+ */
+ fake->packet->id = fake->number & 0xff;
+ fake->packet->code = request->packet->code;
+ fake->timestamp = request->timestamp;
+ fake->packet->timestamp = request->packet->timestamp;
+
+ /*
+ * Required for new identity support
+ */
+ fake->listener = request->listener;
+
+ /*
+ * Fill in the fake reply, based on the fake request.
+ */
+ fake->reply->sockfd = fake->packet->sockfd;
+ fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
+ fake->reply->src_port = fake->packet->dst_port;
+ fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
+ fake->reply->dst_port = fake->packet->src_port;
+ fake->reply->id = fake->packet->id;
+ fake->reply->code = 0; /* UNKNOWN code */
+
+ /*
+ * Copy debug information.
+ */
+ memcpy(&(fake->log), &(request->log), sizeof(fake->log));
+
+ return fake;
}
#ifdef WITH_COA
/*
* Originate CoA requests only when necessary.
*/
- if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
- (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
+ if ((request->packet->code != PW_CODE_ACCESS_REQUEST) &&
+ (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
request->coa = request_alloc_fake(request);
if (!request->coa) return NULL;
request->coa->packet->code = 0; /* unknown, as of yet */
request->coa->child_state = REQUEST_RUNNING;
- request->coa->proxy = rad_alloc(request->coa, 0);
+ request->coa->proxy = rad_alloc(request->coa, false);
if (!request->coa->proxy) {
- request_free(&request->coa);
+ TALLOC_FREE(request->coa);
return NULL;
}
/*
* Copy a quoted string.
*/
-int rad_copy_string(char *to, const char *from)
+int rad_copy_string(char *to, char const *from)
{
int length = 0;
char quote = *from;
* returned is the number of chars written; the number of
* characters consumed is 2 more than this.
*/
-int rad_copy_string_bare(char *to, const char *from)
+int rad_copy_string_bare(char *to, char const *from)
{
int length = 0;
char quote = *from;
/*
* Copy a %{} string.
*/
-int rad_copy_variable(char *to, const char *from)
+int rad_copy_variable(char *to, char const *from)
{
int length = 0;
int sublen;
#define USEC 1000000
#endif
-int rad_pps(int *past, int *present, time_t *then, struct timeval *now)
+uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
{
- int pps;
+ uint32_t pps;
if (*then != now->tv_sec) {
*then = now->tv_sec;
return pps;
}
-/*
- * Split a string into words, xlat each one and write into argv array.
- * Return argc or -1 on failure.
+/** Split string into words and expand each one
+ *
+ * @param request Current request.
+ * @param cmd string to split.
+ * @param max_argc the maximum number of arguments to split into.
+ * @param argv Where to write the pointers into argv_buf.
+ * @param can_fail If false, stop processing if any of the xlat expansions fail.
+ * @param argv_buflen size of argv_buf.
+ * @param argv_buf temporary buffer we used to mangle/expand cmd.
+ * Pointers to offsets of this buffer will be written to argv.
+ * @return argc or -1 on failure.
*/
-int rad_expand_xlat(REQUEST *request, const char *cmd,
- int max_argc, const char *argv[], int can_fail,
+int rad_expand_xlat(REQUEST *request, char const *cmd,
+ int max_argc, char *argv[], bool can_fail,
size_t argv_buflen, char *argv_buf)
{
- const char *from;
+ char const *from;
char *to;
int argc = -1;
int i;
int left;
if (strlen(cmd) > (argv_buflen - 1)) {
- DEBUGE("rad_expand_xlat: Command line is too long");
+ ERROR("rad_expand_xlat: Command line is too long");
return -1;
}
* Check for bad escapes.
*/
if (cmd[strlen(cmd) - 1] == '\\') {
- DEBUGE("rad_expand_xlat: Command line has final backslash, without a following character");
+ ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
return -1;
}
*/
while (*from && (*from != ' ') && (*from != '\t')) {
if (to >= argv_buf + argv_buflen - 1) {
- DEBUGE("rad_expand_xlat: Ran out of space in command line");
+ ERROR("rad_expand_xlat: Ran out of space in command line");
return -1;
}
case '\'':
length = rad_copy_string_bare(to, from);
if (length < 0) {
- DEBUGE("rad_expand_xlat: Invalid string passed as argument");
+ ERROR("rad_expand_xlat: Invalid string passed as argument");
return -1;
}
from += length+2;
length = rad_copy_variable(to, from);
if (length < 0) {
- DEBUGE("rad_expand_xlat: Invalid variable expansion passed as argument");
+ ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
return -1;
}
from += length;
* We have to have SOMETHING, at least.
*/
if (argc <= 0) {
- DEBUGE("rad_expand_xlat: Empty command line.");
+ ERROR("rad_expand_xlat: Empty command line");
return -1;
}
*/
sublen = 0;
} else {
- DEBUGE("rad_expand_xlat: xlat failed");
+ ERROR("rad_expand_xlat: xlat failed");
return -1;
}
}
left--;
if (left <= 0) {
- DEBUGE("rad_expand_xlat: Ran out of space while expanding arguments.");
+ ERROR("rad_expand_xlat: Ran out of space while expanding arguments");
return -1;
}
}
const FR_NAME_NUMBER pair_lists[] = {
{ "request", PAIR_LIST_REQUEST },
{ "reply", PAIR_LIST_REPLY },
+ { "control", PAIR_LIST_CONTROL }, /* New name should have priority */
{ "config", PAIR_LIST_CONTROL },
- { "control", PAIR_LIST_CONTROL },
#ifdef WITH_PROXY
{ "proxy-request", PAIR_LIST_PROXY_REQUEST },
{ "proxy-reply", PAIR_LIST_PROXY_REPLY },
* @see dict_attrbyname
*
* @param[in,out] name of attribute.
- * @param[in] unknown the list to return if no qualifiers were found.
+ * @param[in] default_list the list to return if no qualifiers were found.
* @return PAIR_LIST_UNKOWN if qualifiers couldn't be resolved to a list.
*/
-pair_lists_t radius_list_name(const char **name, pair_lists_t unknown)
+pair_lists_t radius_list_name(char const **name, pair_lists_t default_list)
{
- const char *p = *name;
- const char *q;
-
+ char const *p = *name;
+ char const *q;
+ pair_lists_t output;
+
/* This should never be a NULL pointer or zero length string */
rad_assert(name && *name);
/*
- * We couldn't determine the list if:
- *
- * A colon delimiter was found, but the next char was a
- * number, indicating a tag, not a list qualifier.
- *
- * No colon was found and the first char was upper case
- * indicating an attribute.
- *
+ * Unfortunately, ':' isn't a definitive separator for
+ * the list name. We may have numeric tags, too.
*/
q = strchr(p, ':');
- if (((q && (q[1] >= '0') && (q[1] <= '9'))) ||
- (!q && isupper((int) *p))) {
- return unknown;
- }
-
if (q) {
- *name = (q + 1); /* Consume the list and delimiter */
- } else {
- q = (p + strlen(p)); /* Consume the entire string */
+ /*
+ * Check for tagged attributes. They have
+ * "name:tag", where tag is a decimal number.
+ * Valid tags are invalid attributes, so that's
+ * OK.
+ *
+ * Also allow "name:tag[#]" as a tag.
+ *
+ * However, "request:" is allowed, too, and
+ * shouldn't be interpreted as a tag.
+ *
+ * We do this check first rather than just
+ * looking up the request name, because this
+ * check is cheap, and looking up the request
+ * name is expensive.
+ */
+ if (isdigit((int) q[1])) {
+ char const *d = q + 1;
+
+ while (isdigit((int) *d)) {
+ d++;
+ }
+
+ /*
+ * Return the DEFAULT list as supplied by
+ * the caller. This is usually
+ * PAIRLIST_REQUEST.
+ */
+ if (!*d || (*d == '[')) {
+ return default_list;
+ }
+ }
+
+ /*
+ * If the first part is a list name, then treat
+ * it as a list. This means that we CANNOT have
+ * an attribute which is named "request",
+ * "reply", etc. Allowing a tagged attribute
+ * "request:3" would just be insane.
+ */
+ output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ if (output != PAIR_LIST_UNKNOWN) {
+ *name = (q + 1); /* Consume the list and delimiter */
+ return output;
+ }
+
+ /*
+ * It's not a known list, say so.
+ */
+ return PAIR_LIST_UNKNOWN;
+ }
+
+ /*
+ * The input string may be just a list name,
+ * e.g. "request". Check for that.
+ */
+ q = (p + strlen(p));
+ output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ if (output != PAIR_LIST_UNKNOWN) {
*name = q;
+ return output;
}
-
- return fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+
+ /*
+ * It's just an attribute name. Return the default list
+ * as supplied by the caller.
+ */
+ return default_list;
}
* @param[in] def default request ref to return if no request qualifier is present.
* @return one of the REQUEST_* definitions or REQUEST_UNKOWN
*/
-request_refs_t radius_request_name(const char **name, request_refs_t def)
+request_refs_t radius_request_name(char const **name, request_refs_t def)
{
char *p;
int request;
p = strchr(*name, '.');
if (!p) {
- return REQUEST_CURRENT;
+ return def;
}
-
+
/*
* We may get passed "127.0.0.1".
*/
p - *name);
/*
- * If we get a VALID LIST, skip it.
+ * If we get a valid name, skip it.
*/
if (request != REQUEST_UNKNOWN) {
*name = p + 1;
int radius_request(REQUEST **context, request_refs_t name)
{
REQUEST *request = *context;
-
+
switch (name) {
case REQUEST_CURRENT:
return 0;
-
+
case REQUEST_PARENT: /* for future use in request chaining */
case REQUEST_OUTER:
if (!request->parent) {
- RDEBUGW("Specified request \"%s\" is not available in this context",
- fr_int2str(request_refs, name, "¿unknown?"));
return -1;
}
-
*context = request->parent;
-
break;
-
+
case REQUEST_UNKNOWN:
default:
rad_assert(0);
return -1;
}
-
+
return 0;
}
+/** Adds subcapture values to request data
+ *
+ * Allows use of %{n} expansions.
+ *
+ * @param request Current request.
+ * @param compare Result returned by regexec.
+ * @param value The original value.
+ * @param rxmatch Pointers into value.
+ */
+void rad_regcapture(REQUEST *request, int compare, char const *value, regmatch_t rxmatch[])
+{
+ int i;
+ char *p;
+ size_t len;
+
+ if (compare == REG_NOMATCH) {
+ return;
+ }
+
+ /*
+ * Add new %{0}, %{1}, etc.
+ */
+ for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
+ /*
+ * Didn't match: delete old match, if it existed.
+ */
+ if (rxmatch[i].rm_so == -1) {
+ p = request_data_get(request, request, REQUEST_DATA_REGEX | i);
+ if (p) {
+ RDEBUG4("%%{%i}: Clearing old value \"%s\"", i, p);
+ talloc_free(p);
+ } else {
+ RDEBUG4("%%{%i}: Was empty", i);
+ }
+
+ continue;
+ }
+
+ len = rxmatch[i].rm_eo - rxmatch[i].rm_so;
+ p = talloc_array(request, char, len + 1);
+ if (!p) {
+ ERROR("Out of memory");
+ return;
+ }
+
+ memcpy(p, value + rxmatch[i].rm_so, len);
+ p[len] = '\0';
+
+ RDEBUG4("%%{%i}: Inserting new value \"%s\"", i, p);
+ /*
+ * Copy substring, and add it to
+ * the request.
+ *
+ * Note that we don't check
+ * for out of memory, which is
+ * the only error we can get...
+ */
+ request_data_add(request, request, REQUEST_DATA_REGEX | i, p, true);
+ }
+}
+
+#ifndef NDEBUG
+/*
+ * Verify a packet.
+ */
+static void verify_packet(char const *file, int line, REQUEST *request, RADIUS_PACKET *packet, char const *type)
+{
+ TALLOC_CTX *parent;
+
+ if (!packet) {
+ fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%u]: RADIUS_PACKET %s pointer was NULL", file, line, type);
+ fr_assert(0);
+ fr_exit_now(0);
+ }
+
+ parent = talloc_parent(packet);
+ if (parent != request) {
+ ERROR("CONSISTENCY CHECK FAILED %s[%u]: Expected RADIUS_PACKET %s to be parented by %p (%s), "
+ "but parented by %p (%s)", file, line, type, request, talloc_get_name(request),
+ parent, parent ? talloc_get_name(parent) : "NULL");
+
+ fr_log_talloc_report(packet);
+ if (parent) fr_log_talloc_report(parent);
+
+ rad_assert(0);
+ }
+
+ VERIFY_PACKET(packet);
+
+ if (!packet->vps) return;
+
+#ifdef WITH_VERIFY_PTR
+ fr_verify_list(file, line, packet, packet->vps);
+#endif
+}
+/*
+ * Catch horrible talloc errors.
+ */
+void verify_request(char const *file, int line, REQUEST *request)
+{
+ if (!request) {
+ fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%u]: REQUEST pointer was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(0);
+ }
+
+ (void) talloc_get_type_abort(request, REQUEST);
+
+#ifdef WITH_VERIFY_PTR
+ fr_verify_list(file, line, request, request->config_items);
+#endif
+
+ if (request->packet) verify_packet(file, line, request, request->packet, "request");
+ if (request->reply) verify_packet(file, line, request, request->reply, "reply");
+#ifdef WITH_PROXY
+ if (request->proxy) verify_packet(file, line, request, request->proxy, "proxy-request");
+ if (request->proxy_reply) verify_packet(file, line, request, request->proxy_reply, "proxy-reply");
+#endif
+
+#ifdef WITH_COA
+ if (request->coa) {
+ void *parent;
+
+ (void) talloc_get_type_abort(request->coa, REQUEST);
+ parent = talloc_parent(request->coa);
+
+ rad_assert(parent == request);
+
+ verify_request(file, line, request->coa);
+ }
+#endif
+}
+#endif