예제 #1
0
static int do_regex(REQUEST *request, const char *lhs, const char *rhs, int iflag)
{
	int i, compare;
	int cflags = REG_EXTENDED;
	regex_t reg;
	regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

	if (iflag) cflags |= REG_ICASE;

	/*
	 *	Include substring matches.
	 */
	compare = regcomp(&reg, rhs, cflags);
	if (compare != 0) {
		if (debug_flag) {
			char errbuf[128];

			regerror(compare, &reg, errbuf, sizeof(errbuf));
			EDEBUG("Failed compiling regular expression: %s", errbuf);
		}
		EVAL_DEBUG("FAIL %d", __LINE__);
		return -1;
	}
	
	compare = regexec(&reg, lhs, REQUEST_MAX_REGEX + 1, rxmatch, 0);
	regfree(&reg);

	/*
	 *	Add new %{0}, %{1}, etc.
	 */
	if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
		char *r;
			
		free(request_data_get(request, request,
				      REQUEST_DATA_REGEX | i));
		
		/*
		 *	No %{i}, skip it.
		 *	We MAY have %{2} without %{1}.
		 */
		if (rxmatch[i].rm_so == -1) continue;
		
		/*
		 *	Copy substring into allocated buffer
		 */
		r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1);
		memcpy(r, lhs + rxmatch[i].rm_so,
		       rxmatch[i].rm_eo - rxmatch[i].rm_so);
		r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

		request_data_add(request, request,
				 REQUEST_DATA_REGEX | i,
				 r, free);
		}
	return (compare == 0);
}
예제 #2
0
/** Delete a previously set file descriptor callback
 *
 * param[in] request the request
 * param[in] fd the file descriptor
 * @return
 *	- 0 on success.
 *	- <0 on error.
 */
int unlang_module_fd_delete(REQUEST *request, void const *ctx, int fd)
{
	unlang_module_event_t *ev;

	ev = request_data_get(request, ctx, fd);
	if (!ev) return -1;

	talloc_free(ev);
	return 0;
}
예제 #3
0
/** Delete a previously set timeout callback
 *
 * @param[in] request	The current request.
 * @param[in] ctx	a local context for the callback.
 * @return
 *	- -1 on error.
 *	- 0 on success.
 */
int unlang_module_timeout_delete(REQUEST *request, void const *ctx)
{
	unlang_module_event_t *ev;

	ev = request_data_get(request, ctx, UNLANG_TYPE_MODULE);
	if (!ev) return -1;
	talloc_free(ev);

	return 0;
}
예제 #4
0
/** Send a fake request to a virtual server, managing the eap_session_t of the child
 *
 * If eap_session_t has a child, inject that into the fake request.
 *
 * If after the request has run, the child eap_session_t is no longer present,
 * we assume it has been freed, and fixup the parent eap_session_t.
 *
 * If the eap_session_t pointer changes, this is considered a fatal error.
 *
 * @param request the current (real) request.
 * @param eap_session representing the outer eap method.
 * @param fake request we're going to send.
 * @param virtual_server The default virtual server to send the request to.
 * @return the rcode of the last executed section in the virtual server.
 */
rlm_rcode_t eap_virtual_server(REQUEST *request, REQUEST *fake,
			       eap_session_t *eap_session, char const *virtual_server)
{
	eap_session_t	*inner_eap;
	rlm_rcode_t	rcode;
	VALUE_PAIR	*vp;

	vp = fr_pair_find_by_num(request->config, 0, PW_VIRTUAL_SERVER, TAG_ANY);
	fake->server = vp ? vp->vp_strvalue : virtual_server;

	if (fake->server) {
		RDEBUG2("Sending tunneled request to %s", fake->server);
	} else {
		RDEBUG2("Sending tunnelled request");
	}

	/*
	 *	Add a previously recorded inner eap_session_t back
	 *	to the request.  This in theory allows infinite
	 *	nesting, but this is probably limited somewhere.
	 */
	if (eap_session->child) {
		RDEBUG4("Adding eap_session_t %p to fake request", eap_session->child);
		request_data_add(fake, NULL, REQUEST_DATA_EAP_SESSION, eap_session->child, false, false, false);
	}
	rcode = rad_virtual_server(fake);
	inner_eap = request_data_get(fake, NULL, REQUEST_DATA_EAP_SESSION);
	if (inner_eap) {
		if (!eap_session->child || (eap_session->child != inner_eap)) {
			RDEBUG4("Binding lifetime of child eap_session %p to parent eap_session %p",
				inner_eap, eap_session);
			fr_talloc_link_ctx(eap_session, inner_eap);
			eap_session->child = inner_eap;
		} else {
			RDEBUG4("Got eap_session_t %p back unmolested", eap_session->child);
		}
	/*
	 *	Assume the inner server freed the
	 *	eap_session_t and remove our reference to it.
	 *
	 *	If it didn't actually free the child (due to error)
	 *	the call to talloc_link_ctx (above) ensures it will
	 *	be freed when the parent is.
	 */
	} else if (eap_session->child) {
		RDEBUG4("Inner server freed eap_session %p", eap_session->child);
		eap_session->child = NULL;
	}

	return rcode;
}
예제 #5
0
/** Adds subcapture values to request data
 *
 * Allows use of %{n} expansions.
 *
 * @note If preg was runtime-compiled, it will be consumed and *preg will be set to NULL.
 * @note regmatch will be consumed and *regmatch will be set to NULL.
 * @note Their lifetimes will be bound to the match request data.
 *
 * @param[in] request		Current request.
 * @param[in,out] preg		Compiled pattern. May be set to NULL if
 *				reparented to the regcapture struct.
 * @param[in,out] regmatch	Pointers into value. May be set to NULL if
 *				reparented to the regcapture struct.
 */
void regex_sub_to_request(REQUEST *request, regex_t **preg, fr_regmatch_t **regmatch)
{
	fr_regcapture_t *old_rc, *new_rc;	/* lldb doesn't like bare new *sigh* */

	/*
	 *	Clear out old_rc matches
	 */
	old_rc = request_data_get(request, request, REQUEST_DATA_REGEX);
	if (old_rc) {
		DEBUG4("Clearing %zu matches", old_rc->regmatch->used);
		talloc_free(old_rc);
	} else {
		DEBUG4("No matches");
	}

	if (!regmatch || ((*regmatch)->used == 0)) return;

	rad_assert(preg && *preg);
	rad_assert(regmatch);

	DEBUG4("Adding %zu matches", (*regmatch)->used);

	/*
	 *	Container struct for all the match data
	 */
	MEM(new_rc = talloc(request, fr_regcapture_t));

	/*
	 *	Steal runtime pregs, leave precompiled ones
	 */
#if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
	if (!(*preg)->precompiled) {
		new_rc->preg = talloc_steal(new_rc, *preg);
		*preg = NULL;
	} else {
		new_rc->preg = *preg;	/* Compiled on startup, will hopefully stick around */
	}
#endif

	/*
	 *	Steal match data
	 */
	new_rc->regmatch = talloc_steal(new_rc, *regmatch);
	*regmatch = NULL;

	request_data_talloc_add(request, request, REQUEST_DATA_REGEX, fr_regcapture_t, new_rc, true, false, false);
}
예제 #6
0
/**
 * @brief Compares check and vp by value. Does not call any per-attribute
 *        comparison function, but does honour check.operator
 *
 * This function basically does "vp.value check.op check.value"
 *
 * @param request Current request
 * @param check rvalue, and operator
 * @param vp lvalue
 */
int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
{
	int ret = -2;

	/*
	 *      Check for =* and !* and return appropriately
	 */
	if( check->operator == T_OP_CMP_TRUE )
	         return 0;
	if( check->operator == T_OP_CMP_FALSE )
	         return 1;

#ifdef HAVE_REGEX_H
	if (check->operator == T_OP_REG_EQ) {
		int i, compare;
		regex_t reg;
		char name[1024];
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		snprintf(name, sizeof(name), "%%{%s}", check->name);
		radius_xlat(value, sizeof(value), name, request, NULL);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s",
			       check->vp_strvalue, buffer);
			return -1;
		}
		compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);

		/*
		 *	Add %{0}, %{1}, etc.
		 */
		for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
			char *p;
			char buffer[sizeof(check->vp_strvalue)];

			/*
			 *	Didn't match: delete old
			 *	match, if it existed.
			 */
			if ((compare != 0) ||
			    (rxmatch[i].rm_so == -1)) {
				p = request_data_get(request, request,
						     REQUEST_DATA_REGEX | i);
				if (p) {
					free(p);
					continue;
				}

				/*
				 *	No previous match
				 *	to delete, stop.
				 */
				break;
			}

			/*
			 *	Copy substring into buffer.
			 */
			memcpy(buffer, value + rxmatch[i].rm_so,
			       rxmatch[i].rm_eo - rxmatch[i].rm_so);
			buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

			/*
			 *	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...
			 */
			p = strdup(buffer);
			request_data_add(request, request,
					 REQUEST_DATA_REGEX | i,
					 p, free);
		}
		if (compare == 0) return 0;
		return -1;
	}

	if (check->operator == T_OP_REG_NE) {
		int compare;
		regex_t reg;
		char name[1024];
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		snprintf(name, sizeof(name), "%%{%s}", check->name);
		radius_xlat(value, sizeof(value), name, request, NULL);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, (char *)check->vp_strvalue,
				  REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s",
			       check->vp_strvalue, buffer);
			return -1;
		}
		compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);

		if (compare != 0) return 0;
		return -1;

	}
#endif

	/*
	 *	Tagged attributes are equal if and only if both the
	 *	tag AND value match.
	 */
	if (check->flags.has_tag) {
		ret = ((int) vp->flags.tag) - ((int) check->flags.tag);
		if (ret != 0) return ret;
	}

	/*
	 *	Not a regular expression, compare the types.
	 */
	switch(check->type) {
#ifdef ASCEND_BINARY
		/*
		 *	Ascend binary attributes can be treated
		 *	as opaque objects, I guess...
		 */
		case PW_TYPE_ABINARY:
#endif
		case PW_TYPE_OCTETS:
			if (vp->length != check->length) {
				ret = 1; /* NOT equal */
				break;
			}
			ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
				     vp->length);
			break;
		case PW_TYPE_STRING:
			ret = strcmp((char *)vp->vp_strvalue,
				     (char *)check->vp_strvalue);
			break;
		case PW_TYPE_BYTE:
		case PW_TYPE_SHORT:
		case PW_TYPE_INTEGER:
			ret = vp->vp_integer - check->vp_integer;
			break;
		case PW_TYPE_INTEGER64:
			/*
			 *	Don't want integer overflow!
			 */
			if (vp->vp_integer64 < check->vp_integer64) {
				ret = -1;
			} else if (vp->vp_integer64 > check->vp_integer64) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;
		case PW_TYPE_DATE:
			ret = vp->vp_date - check->vp_date;
			break;
		case PW_TYPE_IPADDR:
			ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
			break;
		case PW_TYPE_IPV6ADDR:
			ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
				     sizeof(vp->vp_ipv6addr));
			break;

		case PW_TYPE_IPV6PREFIX:
			ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
				     sizeof(vp->vp_ipv6prefix));
			break;

		case PW_TYPE_IFID:
			ret = memcmp(&vp->vp_ifid, &check->vp_ifid,
				     sizeof(vp->vp_ifid));
			break;

		default:
			break;
	}

	return ret;
}
예제 #7
0
/*
 *	*presult is "did comparison match or not"
 */
static int radius_do_cmp(REQUEST *request, int *presult,
			 FR_TOKEN lt, const char *pleft, FR_TOKEN token,
			 FR_TOKEN rt, const char *pright,
			 int cflags, int modreturn)
{
	int result;
	uint32_t lint, rint;
	VALUE_PAIR *vp = NULL;
#ifdef HAVE_REGEX_H
	char buffer[8192];
#else
	cflags = cflags;	/* -Wunused */
#endif

	rt = rt;		/* -Wunused */

	if (lt == T_BARE_WORD) {
		/*
		 *	Maybe check the last return code.
		 */
		if (token == T_OP_CMP_TRUE) {
			int isreturn;

			/*
			 *	Looks like a return code, treat is as such.
			 */
			isreturn = fr_str2int(modreturn_table, pleft, -1);
			if (isreturn != -1) {
				*presult = (modreturn == isreturn);
				return TRUE;
			}
		}

		/*
		 *	Bare words on the left can be attribute names.
		 */
		if (radius_get_vp(request, pleft, &vp)) {
			VALUE_PAIR myvp;

			/*
			 *	VP exists, and that's all we're looking for.
			 */
			if (token == T_OP_CMP_TRUE) {
				*presult = (vp != NULL);
				return TRUE;
			}

			if (!vp) {
				DICT_ATTR *da;
				
				/*
				 *	The attribute on the LHS may
				 *	have been a dynamically
				 *	registered callback.  i.e. it
				 *	doesn't exist as a VALUE_PAIR.
				 *	If so, try looking for it.
				 */
				da = dict_attrbyname(pleft);
				if (da && (da->vendor == 0) && radius_find_compare(da->attr)) {
					VALUE_PAIR *check = pairmake(pleft, pright, token);
					*presult = (radius_callback_compare(request, NULL, check, NULL, NULL) == 0);
					RDEBUG3("  Callback returns %d",
						*presult);
					pairfree(&check);
					return TRUE;
				}
				
				RDEBUG2("    (Attribute %s was not found)",
				       pleft);
				*presult = 0;
				return TRUE;
			}

#ifdef HAVE_REGEX_H
			/*
			 * 	Regex comparisons treat everything as
			 *	strings.
			 */
			if ((token == T_OP_REG_EQ) ||
			    (token == T_OP_REG_NE)) {
				vp_prints_value(buffer, sizeof(buffer), vp, 0);
				pleft = buffer;
				goto do_checks;
			}
#endif

			memcpy(&myvp, vp, sizeof(myvp));
			if (!pairparsevalue(&myvp, pright)) {
				RDEBUG2("Failed parsing \"%s\": %s",
				       pright, fr_strerror());
				return FALSE;
			}

			myvp.operator = token;
			*presult = paircmp(&myvp, vp);
			RDEBUG3("  paircmp -> %d", *presult);
			return TRUE;
		} /* else it's not a VP in a list */
	}

#ifdef HAVE_REGEX_H
	do_checks:
#endif
	switch (token) {
	case T_OP_GE:
	case T_OP_GT:
	case T_OP_LE:
	case T_OP_LT:
		if (!all_digits(pright)) {
			RDEBUG2("    (Right field is not a number at: %s)", pright);
			return FALSE;
		}
		rint = strtoul(pright, NULL, 0);
		if (!all_digits(pleft)) {
			RDEBUG2("    (Left field is not a number at: %s)", pleft);
			return FALSE;
		}
		lint = strtoul(pleft, NULL, 0);
		break;
		
	default:
		lint = rint = 0;  /* quiet the compiler */
		break;
	}
	
	switch (token) {
	case T_OP_CMP_TRUE:
		/*
		 *	Check for truth or falsehood.
		 */
		if (all_digits(pleft)) {
			lint = strtoul(pleft, NULL, 0);
			result = (lint != 0);
			
		} else {
			result = (*pleft != '\0');
		}
		break;
		

	case T_OP_CMP_EQ:
		result = (strcmp(pleft, pright) == 0);
		break;
		
	case T_OP_NE:
		result = (strcmp(pleft, pright) != 0);
		break;
		
	case T_OP_GE:
		result = (lint >= rint);
		break;
		
	case T_OP_GT:
		result = (lint > rint);
		break;
		
	case T_OP_LE:
		result = (lint <= rint);
		break;
		
	case T_OP_LT:
		result = (lint < rint);
		break;

#ifdef HAVE_REGEX_H
	case T_OP_REG_EQ: {
		int i, compare;
		regex_t reg;
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
		
		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, pright, cflags);
		if (compare != 0) {
			if (debug_flag) {
				char errbuf[128];

				regerror(compare, &reg, errbuf, sizeof(errbuf));
				DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
			}
			return FALSE;
		}

		compare = regexec(&reg, pleft,
				  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);
		
		/*
		 *	Add new %{0}, %{1}, etc.
		 */
		if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
			char *r;

			free(request_data_get(request, request,
					      REQUEST_DATA_REGEX | i));

			/*
			 *	No %{i}, skip it.
			 *	We MAY have %{2} without %{1}.
			 */
			if (rxmatch[i].rm_so == -1) continue;
			
			/*
			 *	Copy substring into allocated buffer
			 */
			r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1);
			memcpy(r, pleft + rxmatch[i].rm_so,
			       rxmatch[i].rm_eo - rxmatch[i].rm_so);
			r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

			request_data_add(request, request,
					 REQUEST_DATA_REGEX | i,
					 r, free);
		}
		result = (compare == 0);
	}
		break;
		
	case T_OP_REG_NE: {
		int compare;
		regex_t reg;
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
		
		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, pright, cflags);
		if (compare != 0) {
			if (debug_flag) {
				char errbuf[128];

				regerror(compare, &reg, errbuf, sizeof(errbuf));
				DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
			}
			return FALSE;
		}

		compare = regexec(&reg, pleft,
				  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);
		
		result = (compare != 0);
	}
		break;
#endif
		
	default:
		DEBUG("ERROR: Comparison operator %s is not supported",
		      fr_token_name(token));
		result = FALSE;
		break;
	}
	
	*presult = result;
	return TRUE;
}
예제 #8
0
/*
 *	Compare two pair lists except for the password information.
 *	For every element in "check" at least one matching copy must
 *	be present in "reply".
 *
 *	Return 0 on match.
 */
int paircmp(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR **reply)
{
	VALUE_PAIR *check_item;
	VALUE_PAIR *auth_item;
	int result = 0;
	int compare;
	int other;
#ifdef HAVE_REGEX_H
	regex_t reg;
#endif

	for (check_item = check; check_item != NULL; check_item = check_item->next) {
		/*
		 *	If the user is setting a configuration value,
		 *	then don't bother comparing it to any attributes
		 *	sent to us by the user.  It ALWAYS matches.
		 */
		if ((check_item->operator == T_OP_SET) ||
		    (check_item->operator == T_OP_ADD)) {
			continue;
		}

		switch (check_item->attribute) {
			/*
			 *	Attributes we skip during comparison.
			 *	These are "server" check items.
			 */
			case PW_CRYPT_PASSWORD:
			case PW_AUTH_TYPE:
			case PW_AUTZ_TYPE:
			case PW_ACCT_TYPE:
			case PW_SESSION_TYPE:
			case PW_STRIP_USER_NAME:
				continue;
				break;

			/*
			 *	IF the password attribute exists, THEN
			 *	we can do comparisons against it.  If not,
			 *	then the request did NOT contain a
			 *	User-Password attribute, so we CANNOT do
			 *	comparisons against it.
			 *
			 *	This hack makes CHAP-Password work..
			 */
			case PW_PASSWORD:
				if (pairfind(request, PW_PASSWORD) == NULL) {
					continue;
				}
				break;
		}

		/*
		 *	See if this item is present in the request.
		 */
		other = otherattr(check_item->attribute);

		auth_item = request;
	try_again:
		for (; auth_item != NULL; auth_item = auth_item->next) {
			if (auth_item->attribute == other || other == 0)
				break;
		}

		/*
		 *	Not found, it's not a match.
		 */
		if (auth_item == NULL) {
			/*
			 *	Didn't find it.  If we were *trying*
			 *	to not find it, then we succeeded.
			 */
			if (check_item->operator == T_OP_CMP_FALSE)
				return 0;
			else
				return -1;
		}

		/*
		 *	Else we found it, but we were trying to not
		 *	find it, so we failed.
		 */
		if (check_item->operator == T_OP_CMP_FALSE)
			return -1;


		/*
		 *	We've got to xlat the string before doing
		 *	the comparison.
		 */
		if (check_item->flags.do_xlat) {
			int rcode;
			char buffer[sizeof(check_item->strvalue)];

			check_item->flags.do_xlat = 0;
			rcode = radius_xlat(buffer, sizeof(buffer),
					    check_item->strvalue,
					    req, NULL);

			/*
			 *	Parse the string into a new value.
			 */
			pairparsevalue(check_item, buffer);
		}

		/*
		 *	OK it is present now compare them.
		 */
		compare = paircompare(req, auth_item, check_item, check, reply);

		switch (check_item->operator) {
			case T_OP_EQ:
			default:
				radlog(L_ERR,  "Invalid operator for item %s: "
						"reverting to '=='", check_item->name);
				/*FALLTHRU*/
		        case T_OP_CMP_TRUE:    /* compare always == 0 */
		        case T_OP_CMP_FALSE:   /* compare always == 1 */
			case T_OP_CMP_EQ:
				if (compare != 0) result = -1;
				break;

			case T_OP_NE:
				if (compare == 0) result = -1;
				break;

			case T_OP_LT:
				if (compare >= 0) result = -1;
				break;

			case T_OP_GT:
				if (compare <= 0) result = -1;
				break;

			case T_OP_LE:
				if (compare > 0) result = -1;
				break;

			case T_OP_GE:
				if (compare < 0) result = -1;
				break;

#ifdef HAVE_REGEX_H
			case T_OP_REG_EQ:
			{
				int i;
				regmatch_t rxmatch[9];

				/*
				 *	Include substring matches.
				 */
				regcomp(&reg, (char *)check_item->strvalue,
					REG_EXTENDED);
				compare = regexec(&reg,
						  (char *)auth_item->strvalue,
						  REQUEST_MAX_REGEX + 1,
						  rxmatch, 0);
				regfree(&reg);

				/*
				 *	Add %{0}, %{1}, etc.
				 */
				for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
					char *p;
					char buffer[sizeof(check_item->strvalue)];

					/*
					 *	Didn't match: delete old
					 *	match, if it existed.
					 */
					if ((compare != 0) ||
					    (rxmatch[i].rm_so == -1)) {
						p = request_data_get(req, req,
								     REQUEST_DATA_REGEX | i);
						if (p) {
							free(p);
							continue;
						}

						/*
						 *	No previous match
						 *	to delete, stop.
						 */
						break;
					}
					
					/*
					 *	Copy substring into buffer.
					 */
					memcpy(buffer,
					       auth_item->strvalue + rxmatch[i].rm_so,
					       rxmatch[i].rm_eo - rxmatch[i].rm_so);
					buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

					/*
					 *	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...
					 */
					p = strdup(buffer);
					request_data_add(req,
							 req,
							 REQUEST_DATA_REGEX | i,
							 p, free);
				}
			}				
				if (compare != 0) result = -1;
				break;

			case T_OP_REG_NE:
				regcomp(&reg, (char *)check_item->strvalue, REG_EXTENDED|REG_NOSUB);
				compare = regexec(&reg, (char *)auth_item->strvalue,
						0, NULL, 0);
				regfree(&reg);
				if (compare == 0) result = -1;
				break;
#endif

		} /* switch over the operator of the check item */

		/*
		 *	This attribute didn't match, but maybe there's
		 *	another of the same attribute, which DOES match.
		 */
		if (result != 0) {
			auth_item = auth_item->next;
			result = 0;
			goto try_again;
		}

	} /* for every entry in the check item list */

	return 0;		/* it matched */
}
예제 #9
0
/*
 *	If we're proxying EAP, then there may be magic we need
 *	to do.
 */
static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
{
	size_t		i;
	size_t		len;
	VALUE_PAIR	*vp;
	eap_handler_t	*handler;

	/*
	 *	Just in case the admin lists EAP in post-proxy-type Fail.
	 */
	if (!request->proxy_reply) return RLM_MODULE_NOOP;

	/*
	 *	If there was a handler associated with this request,
	 *	then it's a tunneled request which was proxied...
	 */
	handler = request_data_get(request, inst, REQUEST_DATA_eap_handler_t);
	if (handler != NULL) {
		rlm_rcode_t rcode;
		eap_tunnel_data_t *data;

		/*
		 *	Grab the tunnel callbacks from the request.
		 */
		data = (eap_tunnel_data_t *) request_data_get(request,
							      request->proxy,
							      REQUEST_DATA_EAP_TUNNEL_CALLBACK);
		if (!data) {
			radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!");
			eap_handler_free(inst, handler);
			return RLM_MODULE_FAIL;
		}

		/*
		 *	Do the callback...
		 */
		RDEBUG2("Doing post-proxy callback");
		rcode = data->callback(handler, data->tls_session);
		free(data);
		if (rcode == 0) {
			RDEBUG2("Failed in post-proxy callback");
			eap_fail(handler);
			eap_handler_free(inst, handler);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	We are done, wrap the EAP-request in RADIUS to send
		 *	with all other required radius attributes
		 */
		eap_compose(handler);

		/*
		 *	Add to the list only if it is EAP-Request, OR if
		 *	it's LEAP, and a response.
		 */
		if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
		    (handler->eap_ds->request->type.num >= PW_EAP_MD5)) {
			if (!eaplist_add(inst, handler)) {
				eap_fail(handler);
				eap_handler_free(inst, handler);
				return RLM_MODULE_FAIL;
			}
			
		} else {	/* couldn't have been LEAP, there's no tunnel */
			RDEBUG2("Freeing handler");
			/* handler is not required any more, free it now */
			eap_handler_free(inst, handler);
		}

		/*
		 *	If it's an Access-Accept, RFC 2869, Section 2.3.1
		 *	says that we MUST include a User-Name attribute in the
		 *	Access-Accept.
		 */
		if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
		    request->username) {
			/*
			 *	Doesn't exist, add it in.
			 */
			vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
			if (!vp) {
				pairmake_reply("User-Name",
					       request->username->vp_strvalue,
					       T_OP_EQ);
			}
		}

		return RLM_MODULE_OK;
	} else {
		RDEBUG2("No pre-existing handler found");
	}

	/*
	 *	There may be more than one Cisco-AVPair.
	 *	Ensure we find the one with the LEAP attribute.
	 */
	vp = request->proxy_reply->vps;
	for (;;) {
		/*
		 *	Hmm... there's got to be a better way to
		 *	discover codes for vendor attributes.
		 *
		 *	This is vendor Cisco (9), Cisco-AVPair
		 *	attribute (1)
		 */
		vp = pairfind(vp, 1, 9, TAG_ANY);
		if (!vp) {
			return RLM_MODULE_NOOP;
		}

		/*
		 *	If it's "leap:session-key", then stop.
		 *
		 *	The format is VERY specific!
		 */
		if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) {
			break;
		}

		/*
		 *	Not this AV-pair.  Go to the next one.
		 */
		vp = vp->next;
	}

	/*
	 *	The format is very specific.
	 */
	if (vp->length != 17 + 34) {
		RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
		       vp->length, 17 + 34);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Decrypt the session key, using the proxy data.
	 */
	i = 34;			/* starts off with 34 octets */
	len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i,
				  request->home_server->secret,
				  request->proxy->vector);

	/*
	 *	FIXME: Assert that i == 16.
	 */

	/*
	 *	Encrypt the session key again, using the request data.
	 */
	rad_tunnel_pwencode(vp->vp_strvalue + 17, &len,
			    request->client->secret,
			    request->packet->vector);

	return RLM_MODULE_UPDATED;
}
static int do_attr_rewrite(void *instance, REQUEST *request)
{
	rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
	int ret = RLM_MODULE_NOOP;
	VALUE_PAIR *attr_vp = NULL;
	VALUE_PAIR *tmp = NULL;
	regex_t preg;
	regmatch_t pmatch[9];
	int cflags = 0;
	int err = 0;
	char done_xlat = 0;
	unsigned int len = 0;
	char err_msg[MAX_STRING_LEN];
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int counter = 0;
	char new_str[MAX_STRING_LEN];
	char *ptr, *ptr2;
	char search_STR[MAX_STRING_LEN];
	char replace_STR[MAX_STRING_LEN];

	if ((attr_vp = pairfind(request->config_items, PW_REWRITE_RULE)) != NULL){
		if (data->name == NULL || strcmp(data->name,attr_vp->vp_strvalue))
			return RLM_MODULE_NOOP;
	}

	if (data->new_attr){
		/* new_attribute = yes */
		if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) {
			DEBUG2("%s: xlat on replace string failed.", data->name);
			return ret;
		}
		attr_vp = pairmake(data->attribute,replace_STR,0);
		if (attr_vp == NULL){
			DEBUG2("%s: Could not add new attribute %s with value '%s'", data->name,
				data->attribute,replace_STR);
			return ret;
		}
		switch(data->searchin){
			case RLM_REGEX_INPACKET:
				pairadd(&request->packet->vps,attr_vp);
				break;
			case RLM_REGEX_INCONFIG:
				pairadd(&request->config_items,attr_vp);
				break;
			case RLM_REGEX_INREPLY:
				pairadd(&request->reply->vps,attr_vp);
				break;
			case RLM_REGEX_INPROXY:
				if (!request->proxy) {
					pairbasicfree(attr_vp);
					return RLM_MODULE_NOOP;
				}
				pairadd(&request->proxy->vps, attr_vp);
				break;
			case RLM_REGEX_INPROXYREPLY:
				if (!request->proxy_reply) {
					pairbasicfree(attr_vp);
					return RLM_MODULE_NOOP;
				}
				pairadd(&request->proxy_reply->vps, attr_vp);
				break;
			default:
				radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
				data->searchin = RLM_REGEX_INPACKET;
				pairadd(&request->packet->vps,attr_vp);
				break;
		}
		DEBUG2("%s: Added attribute %s with value '%s'", data->name,data->attribute,replace_STR);
		ret = RLM_MODULE_OK;
	} else {
		int replace_len = 0;

		/* new_attribute = no */
		switch (data->searchin) {
			case RLM_REGEX_INPACKET:
				if (data->attr_num == PW_USER_NAME)
					attr_vp = request->username;
				else if (data->attr_num == PW_USER_PASSWORD)
					attr_vp = request->password;
				else
					tmp = request->packet->vps;
				break;
			case RLM_REGEX_INCONFIG:
				tmp = request->config_items;
				break;
			case RLM_REGEX_INREPLY:
				tmp = request->reply->vps;
				break;
			case RLM_REGEX_INPROXYREPLY:
				if (!request->proxy_reply)
					return RLM_MODULE_NOOP;
				tmp = request->proxy_reply->vps;
				break;
			case RLM_REGEX_INPROXY:
				if (!request->proxy)
					return RLM_MODULE_NOOP;
				tmp = request->proxy->vps;
				break;
			default:
				radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
				data->searchin = RLM_REGEX_INPACKET;
				attr_vp = pairfind(request->packet->vps, data->attr_num);
				break;
		}
do_again:
		if (tmp != NULL)
			attr_vp = pairfind(tmp, data->attr_num);
		if (attr_vp == NULL) {
			DEBUG2("%s: Could not find value pair for attribute %s", data->name,data->attribute);
			return ret;
		}
		if (attr_vp->vp_strvalue == NULL || attr_vp->length == 0){
			DEBUG2("%s: Attribute %s string value NULL or of zero length", data->name,data->attribute);
			return ret;
		}
		cflags |= REG_EXTENDED;
		if (data->nocase)
			cflags |= REG_ICASE;

		if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL) && data->search_len != 0) {
			DEBUG2("%s: xlat on search string failed.", data->name);
			return ret;
		}

		if ((err = regcomp(&preg,search_STR,cflags))) {
			regerror(err, &preg, err_msg, MAX_STRING_LEN);
			DEBUG2("%s: regcomp() returned error: %s", data->name,err_msg);
			return ret;
		}

		if ((attr_vp->type == PW_TYPE_IPADDR) &&
		    (attr_vp->vp_strvalue[0] == '\0')) {
			inet_ntop(AF_INET, &(attr_vp->vp_ipaddr),
				  attr_vp->vp_strvalue,
				  sizeof(attr_vp->vp_strvalue));
		}

		ptr = new_str;
		ptr2 = attr_vp->vp_strvalue;
		counter = 0;

		for ( i = 0 ;i < (unsigned)data->num_matches; i++) {
			err = regexec(&preg, ptr2, REQUEST_MAX_REGEX, pmatch, 0);
			if (err == REG_NOMATCH) {
				if (i == 0) {
					DEBUG2("%s: Does not match: %s = %s", data->name,
							data->attribute, attr_vp->vp_strvalue);
					regfree(&preg);
					goto to_do_again;
				} else
					break;
			}
			if (err != 0) {
				regfree(&preg);
				radlog(L_ERR, "%s: match failure for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}
			if (pmatch[0].rm_so == -1)
				break;
			len = pmatch[0].rm_so;
			if (data->append) {
				len = len + (pmatch[0].rm_eo - pmatch[0].rm_so);
			}
			counter += len;
			if (counter >= MAX_STRING_LEN) {
				regfree(&preg);
				DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}

			memcpy(ptr, ptr2,len);
			ptr += len;
			*ptr = '\0';
			ptr2 += pmatch[0].rm_eo;

			if (i == 0){
				/*
				 * We only run on the first match, sorry
				 */
				for(j = 0; j <= REQUEST_MAX_REGEX; j++){
					char *p;
					char buffer[sizeof(attr_vp->vp_strvalue)];

					/*
				   	 * Stolen from src/main/valuepair.c, paircompare()
				 	 */

					/*
					 * Delete old matches if the corresponding match does not
					 * exist in the current regex
					 */
					if (pmatch[j].rm_so == -1){
						p = request_data_get(request,request,REQUEST_DATA_REGEX | j);
						if (p){
							free(p);
							continue;
						}
						break;
					}
					memcpy(buffer,
					       attr_vp->vp_strvalue + pmatch[j].rm_so,
					       pmatch[j].rm_eo - pmatch[j].rm_so);
					buffer[pmatch[j].rm_eo - pmatch[j].rm_so] = '\0';
					p = strdup(buffer);
					request_data_add(request,request,REQUEST_DATA_REGEX | j,p,free);
				}
			}

			if (!done_xlat){
				if (data->replace_len != 0 &&
				radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL) == 0) {
					DEBUG2("%s: xlat on replace string failed.", data->name);
					return ret;
				}
				replace_len = (data->replace_len != 0) ? strlen(replace_STR) : 0;
				done_xlat = 1;
			}

			counter += replace_len;
			if (counter >= MAX_STRING_LEN) {
				regfree(&preg);
				DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}
			if (replace_len){
				memcpy(ptr, replace_STR, replace_len);
				ptr += replace_len;
				*ptr = '\0';
			}
		}
		regfree(&preg);
		len = strlen(ptr2) + 1;		/* We add the ending NULL */
		counter += len;
		if (counter >= MAX_STRING_LEN){
			DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
					data->attribute, attr_vp->vp_strvalue);
			return ret;
		}
		memcpy(ptr, ptr2, len);
		ptr[len] = '\0';

		DEBUG2("%s: Changed value for attribute %s from '%s' to '%s'", data->name,
				data->attribute, attr_vp->vp_strvalue, new_str);
		if (pairparsevalue(attr_vp, new_str) == NULL) {
			DEBUG2("%s: Could not write value '%s' into attribute %s: %s", data->name, new_str, data->attribute, fr_strerror());
			return ret;
		}

to_do_again:
		ret = RLM_MODULE_OK;

		if (tmp != NULL){
			tmp = attr_vp->next;
			if (tmp != NULL)
				goto do_again;
		}
	}

	return ret;
}
예제 #11
0
/*
 *	Do post-proxy processing,
 */
static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data)
{
	int rcode;
	tls_session_t *tls_session = (tls_session_t *) data;
	REQUEST *fake, *request = handler->request;

	RDEBUG("Passing reply from proxy back into the tunnel");

	/*
	 *	If there was a fake request associated with the proxied
	 *	request, do more processing of it.
	 */
	fake = (REQUEST *) request_data_get(handler->request,
					    handler->request->proxy,
					    REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);

	/*
	 *	Do the callback, if it exists, and if it was a success.
	 */
	if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) {
		/*
		 *	Terrible hacks.
		 */
		rad_assert(!fake->packet);
		fake->packet = talloc_steal(fake, request->proxy);
		fake->packet->src_ipaddr = request->packet->src_ipaddr;
		request->proxy = NULL;

		rad_assert(!fake->reply);
		fake->reply = talloc_steal(fake, request->proxy_reply);
		request->proxy_reply = NULL;

		if ((rad_debug_lvl > 0) && fr_log_fp) {
			fprintf(fr_log_fp, "server %s {\n",
				(!fake->server) ? "" : fake->server);
		}

		/*
		 *	Perform a post-auth stage for the tunneled
		 *	session.
		 */
		fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
		rcode = rad_postauth(fake);
		RDEBUG2("post-auth returns %d", rcode);

		if ((rad_debug_lvl > 0) && fr_log_fp) {
			fprintf(fr_log_fp, "} # server %s\n",
				(!fake->server) ? "" : fake->server);

			RDEBUG("Final reply from tunneled session code %d", fake->reply->code);
			rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
		}

		/*
		 *	Terrible hacks.
		 */
		request->proxy = talloc_steal(request, fake->packet);
		fake->packet = NULL;
		request->proxy_reply = talloc_steal(request, fake->reply);
		fake->reply = NULL;

		/*
		 *	And we're done with this request.
		 */

		switch (rcode) {
		case RLM_MODULE_FAIL:
			talloc_free(fake);
			eaptls_fail(handler, 0);
			return 0;

		default:  /* Don't Do Anything */
			RDEBUG2("Got reply %d",
			       request->proxy_reply->code);
			break;
		}
	}
	talloc_free(fake);	/* robust if !fake */

	/*
	 *	Process the reply from the home server.
	 */
	rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply);

	/*
	 *	The proxy code uses the reply from the home server as
	 *	the basis for the reply to the NAS.  We don't want that,
	 *	so we toss it, after we've had our way with it.
	 */
	fr_pair_list_free(&handler->request->proxy_reply->vps);

	switch (rcode) {
	case RLM_MODULE_REJECT:
		RDEBUG("Reply was rejected");
		break;

	case RLM_MODULE_HANDLED:
		RDEBUG("Reply was handled");
		eaptls_request(handler->eap_ds, tls_session);
		request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
		return 1;

	case RLM_MODULE_OK:
		RDEBUG("Reply was OK");

		/*
		 *	Success: Automatically return MPPE keys.
		 */
		return eaptls_success(handler, 0);

	default:
		RDEBUG("Reply was unknown");
		break;
	}

	eaptls_fail(handler, 0);
	return 0;
}
예제 #12
0
/*
 *	Evaluate a condition
 */
static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
{
	int rcode;
	const policy_condition_t *this;
	VALUE_PAIR *vp = NULL;
	const char *data = NULL;
	int compare;
#ifdef HAVE_REGEX_H
	regex_t reg;
#endif
	char buffer[256];
	char lhs_buffer[2048];

	this = (const policy_condition_t *) item;

 redo:
	/*
	 *	FIXME: Don't always do this...
	 */
	if (this->compare != POLICY_LEX_L_BRACKET) {
		if (this->lhs_type == POLICY_LEX_FUNCTION) {
			/*
			 *	We can't call evaluate_call here,
			 *	because that just pushes stuff onto
			 *	the stack, and we want to actually
			 *	evaluate all of it...
			 */
			rcode = policy_evaluate_name(state, this->lhs);
			data = fr_int2str(policy_return_codes, rcode, "???");
			strlcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
		} else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
			if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
					state->request, NULL, NULL) > 0) {
				data = lhs_buffer;
			}
		}
	}

	switch (this->compare) {
	case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */
		rcode = evaluate_condition(state, this->child);
		break;

	case POLICY_LEX_L_NOT:
		rcode = evaluate_condition(state, this->child);
		rcode = (rcode == FALSE); /* reverse sense of test */
		break;

	case POLICY_LEX_CMP_FALSE: /* non-existence */
		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			vp = find_vp(state->request, this->lhs);
			rcode = (vp == NULL);
		} else {
			rcode = (data == NULL);
		}
		break;

	case POLICY_LEX_CMP_TRUE: /* existence */
		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			vp = find_vp(state->request, this->lhs);
			rcode = (vp != NULL);
		} else {
			rcode = (data != NULL);
		}
		break;

	default:		/* process other comparisons */
		if ((this->compare != POLICY_LEX_CMP_EQUALS) &&
#ifdef HAVE_REGEX_H
		    (this->compare != POLICY_LEX_RX_EQUALS) &&
		    (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&
#endif
		    (this->compare != POLICY_LEX_LT) &&
		    (this->compare != POLICY_LEX_GT) &&
		    (this->compare != POLICY_LEX_LE) &&
		    (this->compare != POLICY_LEX_GE) &&
		    (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {
			fprintf(stderr, "%d: bad comparison\n",
				this->item.lineno);
			return FALSE;
		}

		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			VALUE_PAIR *myvp;

			vp = find_vp(state->request, this->lhs);

			/*
			 *	A op B is FALSE if A doesn't
			 *	exist.
			 */
			if (!vp) {
				rcode = FALSE;
				break;
			}

			/*
			 *	FIXME: Move sanity checks to
			 *	post-parse code, so we don't do
			 *	it on every packet.
			 */
			vp_prints_value(buffer, sizeof(buffer), vp, 0);
			myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
			if (!myvp) return FALSE; /* memory failure */
			data = buffer;

			/*
			 *	FIXME: What to do about comparisons
			 *	where vp doesn't exist?  Right now,
			 *	"simplepaircmp" returns -1, which is
			 *	probably a bad idea.  it should
			 *	instead take an operator, a pointer to
			 *	the comparison result, and return
			 *	"true/false" for "comparions
			 *	succeeded/failed", which are different
			 *	error codes than "comparison is less
			 *	than, equal to, or greater than zero".
			 */
			compare = radius_callback_compare(state->request,
							  vp, myvp, NULL, NULL);
			pairfree(&myvp);

		} else {
			/*
			 *	FIXME: Do something for RHS type?
			 */
			fr_printf_log("CMP %s %s\n", lhs_buffer, this->rhs);
			compare = strcmp(lhs_buffer, this->rhs);
		}

		debug_evaluate("CONDITION COMPARE %d\n", compare);

		switch (this->compare) {
		case POLICY_LEX_CMP_EQUALS:
			rcode = (compare == 0);
			break;

		case POLICY_LEX_CMP_NOT_EQUALS:
			rcode = (compare != 0);
			break;

		case POLICY_LEX_LT:
			rcode = (compare < 0);
			break;

		case POLICY_LEX_GT:
			rcode = (compare > 0);
			break;

		case POLICY_LEX_LE:
			rcode =(compare <= 0);
			break;

		case POLICY_LEX_GE:
			rcode = (compare >= 0);
			break;

#ifdef HAVE_REGEX_H
		case POLICY_LEX_RX_EQUALS:
		{ /* FIXME: copied from src/main/valuepair.c */
			int i;
			regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

			/*
			 *	Include substring matches.
			 */
			if (regcomp(&reg, this->rhs,
				    REG_EXTENDED) != 0) {
				/* FIXME: print error */
				return FALSE;
			}
			rad_assert(data != NULL);
			rcode = regexec(&reg, data,
					REQUEST_MAX_REGEX + 1,
					rxmatch, 0);
			rcode = (rcode == 0);
			regfree(&reg);

			/*
			 *	Add %{0}, %{1}, etc.
			 */
			for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
				char *p;
				char rxbuffer[256];

				/*
				 *	Didn't match: delete old
				 *	match, if it existed.
				 */
				if (!rcode ||
				    (rxmatch[i].rm_so == -1)) {
					p = request_data_get(state->request, state->request,
							     REQUEST_DATA_REGEX | i);
					if (p) {
						free(p);
						continue;
					}

					/*
					 *	No previous match
					 *	to delete, stop.
					 */
					break;
				}

				/*
				 *	Copy substring into buffer.
				 */
				memcpy(rxbuffer,
				       data + rxmatch[i].rm_so,
				       rxmatch[i].rm_eo - rxmatch[i].rm_so);
				rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

				/*
				 *	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...
				 */
				p = strdup(rxbuffer);
				request_data_add(state->request,
						 state->request,
						 REQUEST_DATA_REGEX | i,
						 p, free);
			}

		}
		break;

		case POLICY_LEX_RX_NOT_EQUALS:
			regcomp(&reg, this->rhs, REG_EXTENDED|REG_NOSUB);
			rad_assert(data != NULL);
			rcode = regexec(&reg, data,
					0, NULL, 0);
			rcode = (rcode != 0);
			regfree(&reg);
				break;
#endif /* HAVE_REGEX_H */
		default:
			rcode = FALSE;
			break;
		} /* switch over comparison operators */
		break;		/* default from first switch over compare */
	}

	if (this->sense) rcode = (rcode == FALSE); /* reverse sense of test */

	/*
	 *	No trailing &&, ||
	 */
	switch (this->child_condition) {
	default:
		return rcode;

	case POLICY_LEX_L_AND:
		if (!rcode) return rcode; /* FALSE && x == FALSE */
		break;

	case POLICY_LEX_L_OR:
		if (rcode) return rcode; /* TRUE && x == TRUE */
		break;
	}

	/*
	 *	Tail recursion.
	 */
	this = (const policy_condition_t *) this->child;
	goto redo;

	return 1;		/* should never reach here */
}
예제 #13
0
static unlang_action_t unlang_foreach(REQUEST *request,
				      rlm_rcode_t *presult, int *priority)
{
	VALUE_PAIR			*vp;
	unlang_stack_t			*stack = request->stack;
	unlang_stack_frame_t		*frame = &stack->frame[stack->depth];
	unlang_t			*instruction = frame->instruction;
	unlang_frame_state_foreach_t	*foreach = NULL;
	unlang_group_t			*g;

	g = unlang_generic_to_group(instruction);

	if (!frame->repeat) {
		int i, foreach_depth = -1;
		VALUE_PAIR *vps;

		if (stack->depth >= UNLANG_STACK_MAX) {
			ERROR("Internal sanity check failed: module stack is too deep");
			fr_exit(EXIT_FAILURE);
		}

		/*
		 *	Figure out how deep we are in nesting by looking at request_data
		 *	stored previously.
		 *
		 *	FIXME: figure this out by walking up the modcall stack instead.
		 */
		for (i = 0; i < 8; i++) {
			if (!request_data_reference(request, (void *)xlat_fmt_get_vp, i)) {
				foreach_depth = i;
				break;
			}
		}

		if (foreach_depth < 0) {
			REDEBUG("foreach Nesting too deep!");
			*presult = RLM_MODULE_FAIL;
			*priority = 0;
			return UNLANG_ACTION_CALCULATE_RESULT;
		}

		/*
		 *	Copy the VPs from the original request, this ensures deterministic
		 *	behaviour if someone decides to add or remove VPs in the set we're
		 *	iterating over.
		 */
		if (tmpl_copy_vps(stack, &vps, request, g->vpt) < 0) {	/* nothing to loop over */
			*presult = RLM_MODULE_NOOP;
			*priority = instruction->actions[RLM_MODULE_NOOP];
			return UNLANG_ACTION_CALCULATE_RESULT;
		}

		MEM(frame->state = foreach = talloc_zero(stack, unlang_frame_state_foreach_t));

		rad_assert(vps != NULL);

		foreach->depth = foreach_depth;
		foreach->vps = vps;
		fr_cursor_talloc_init(&foreach->cursor, &foreach->vps, VALUE_PAIR);
#ifndef NDEBUG
		foreach->indent = request->log.unlang_indent;
#endif

		vp = fr_cursor_head(&foreach->cursor);
	} else {
		foreach = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);

		vp = fr_cursor_next(&foreach->cursor);

		/*
		 *	We've been asked to unwind to the
		 *	enclosing "foreach".  We're here, so
		 *	we can stop unwinding.
		 */
		if (frame->unwind == UNLANG_TYPE_BREAK) {
			frame->unwind = UNLANG_TYPE_NULL;
			vp = NULL;
		}

		/*
		 *	Unwind all the way.
		 */
		if (frame->unwind == UNLANG_TYPE_RETURN) {
			vp = NULL;
		}

		if (!vp) {
			/*
			 *	Free the copied vps and the request data
			 *	If we don't remove the request data, something could call
			 *	the xlat outside of a foreach loop and trigger a segv.
			 */
			fr_pair_list_free(&foreach->vps);
			request_data_get(request, (void *)xlat_fmt_get_vp, foreach->depth);

			*presult = frame->result;
			if (*presult != RLM_MODULE_UNKNOWN) *priority = instruction->actions[*presult];
#ifndef NDEBUG
			rad_assert(foreach->indent == request->log.unlang_indent);
#endif
			return UNLANG_ACTION_CALCULATE_RESULT;
		}
	}

#ifndef NDEBUG
	RDEBUG2("");
	RDEBUG2("# looping with: Foreach-Variable-%d = %pV", foreach->depth, &vp->data);
#endif

	rad_assert(vp);

	/*
	 *	Add the vp to the request, so that
	 *	xlat.c, xlat_foreach() can find it.
	 */
	foreach->variable = vp;
	request_data_add(request, (void *)xlat_fmt_get_vp, foreach->depth, &foreach->variable,
			 false, false, false);

	/*
	 *	Push the child, and yield for a later return.
	 */
	unlang_push(stack, g->children, frame->result, UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME);
	frame->repeat = true;

	return UNLANG_ACTION_PUSHED_CHILD;
}