Esempio n. 1
0
/**
 * @brief Compare check and vp. May call the attribute compare function.
 *
 * Unlike radius_compare_vps() this function will call any attribute-
 * specific comparison function.
 *
 * @param req Current request
 * @param request value pairs in the reqiest
 * @param check erm...
 * @param check_pairs erm...
 * @param reply_pairs value pairs in the reply
 * @return 
 */
int radius_callback_compare(REQUEST *req, VALUE_PAIR *request,
			    VALUE_PAIR *check, VALUE_PAIR *check_pairs,
			    VALUE_PAIR **reply_pairs)
{
	struct cmp *c;

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

	/*
	 *	See if there is a special compare function.
	 *
	 *	FIXME: use new RB-Tree code.
	 */
	for (c = cmp; c; c = c->next)
		if ((c->attribute == check->attribute) &&
		    (check->vendor == 0)) {
			return (c->compare)(c->instance, req, request, check,
				check_pairs, reply_pairs);
		}

	if (!request) return -1; /* doesn't exist, don't compare it */

	return radius_compare_vps(req, check, request);
}
Esempio n. 2
0
/** Check group membership attributes to see if a user is a member.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in] check vp containing the group value (name or dn).
 *
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_check_cached(ldap_instance_t const *inst, REQUEST *request, VALUE_PAIR *check)
{
	VALUE_PAIR	*vp;
	int		ret;
	vp_cursor_t	cursor;

	fr_cursor_init(&cursor, &request->config_items);
	vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY);
	if (!vp) {
		return RLM_MODULE_INVALID;
	}

	for (; vp; vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY)) {
		ret = radius_compare_vps(request, check, vp);
		if (ret == 0) {
			RDEBUG2("User found. Matched cached membership");
			return RLM_MODULE_OK;
		}

		if (ret < -1) {
			return RLM_MODULE_FAIL;
		}
	}

	RDEBUG2("Membership not found");
	return RLM_MODULE_NOTFOUND;
}
Esempio n. 3
0
/** Check group membership attributes to see if a user is a member.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in] check vp containing the group value (name or dn).
 *
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_check_cached(ldap_instance_t const *inst, REQUEST *request, VALUE_PAIR *check)
{
	VALUE_PAIR	*vp;
	int		ret;
	vp_cursor_t	cursor;

	paircursor(&cursor, &request->config_items);
	while ((vp = pairfindnext(&cursor, inst->group_da->attr, inst->group_da->vendor, TAG_ANY))) {
		ret = radius_compare_vps(request, check, vp);
		if (ret == 0) {
			RDEBUG2("User found. Matched cached membership");
			return RLM_MODULE_OK;
		}
		
		if (ret < 0) {
			return RLM_MODULE_FAIL;
		}
	}
	
	RDEBUG2("Membership not found");
	return RLM_MODULE_NOTFOUND;
}
Esempio n. 4
0
/*
 *	The pairmove() function in src/lib/valuepair.c does all sorts of
 *	extra magic that we don't want here.
 *
 *	FIXME: integrate this with the code calling it, so that we
 *	only paircopy() those attributes that we're really going to
 *	use.
 */
void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from)
{
	int i, j, count, from_count, to_count, tailto;
	VALUE_PAIR *vp, *next, **last;
	VALUE_PAIR **from_list, **to_list;
	int *edited = NULL;
	REQUEST *fixup = NULL;

	/*
	 *	Set up arrays for editing, to remove some of the
	 *	O(N^2) dependencies.  This also makes it easier to
	 *	insert and remove attributes.
	 *
	 *	It also means that the operators apply ONLY to the
	 *	attributes in the original list.  With the previous
	 *	implementation of pairmove(), adding two attributes
	 *	via "+=" and then "=" would mean that the second one
	 *	wasn't added, because of the existence of the first
	 *	one in the "to" list.  This implementation doesn't
	 *	have that bug.
	 *
	 *	Also, the previous implementation did NOT implement
	 *	"-=" correctly.  If two of the same attributes existed
	 *	in the "to" list, and you tried to subtract something
	 *	matching the *second* value, then the pairdelete()
	 *	function was called, and the *all* attributes of that
	 *	number were deleted.  With this implementation, only
	 *	the matching attributes are deleted.
	 */
	count = 0;
	for (vp = from; vp != NULL; vp = vp->next) count++;
	from_list = rad_malloc(sizeof(*from_list) * count);

	for (vp = *to; vp != NULL; vp = vp->next) count++;
	to_list = rad_malloc(sizeof(*to_list) * count);

	/*
	 *	Move the lists to the arrays, and break the list
	 *	chains.
	 */
	from_count = 0;
	for (vp = from; vp != NULL; vp = next) {
		next = vp->next;
		from_list[from_count++] = vp;
		vp->next = NULL;
	}

	to_count = 0;
	for (vp = *to; vp != NULL; vp = next) {
		next = vp->next;
		to_list[to_count++] = vp;
		vp->next = NULL;
	}
	tailto = to_count;
	edited = rad_malloc(sizeof(*edited) * to_count);
	memset(edited, 0, sizeof(*edited) * to_count);

	RDEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count);

	/*
	 *	Now that we have the lists initialized, start working
	 *	over them.
	 */
	for (i = 0; i < from_count; i++) {
		int found;

		RDEBUG4("::: Examining %s", from_list[i]->name);

		/*
		 *	Attribute should be appended, OR the "to" list
		 *	is empty, and we're supposed to replace or
		 *	"add if not existing".
		 */
		if (from_list[i]->operator == T_OP_ADD) goto append;

		found = FALSE;
		for (j = 0; j < to_count; j++) {
			if (edited[j] || !to_list[j] || !from_list[i]) continue;

			/*
			 *	Attributes aren't the same, skip them.
			 */
			if ((from_list[i]->attribute != to_list[j]->attribute) ||
			    (from_list[i]->vendor != to_list[j]->vendor)) {
				continue;
			}

			/*
			 *	We don't use a "switch" statement here
			 *	because we want to break out of the
			 *	"for" loop over 'j' in most cases.
			 */

			/*
			 *	Over-write the FIRST instance of the
			 *	matching attribute name.  We free the
			 *	one in the "to" list, and move over
			 *	the one in the "from" list.
			 */
			if (from_list[i]->operator == T_OP_SET) {
				RDEBUG4("::: OVERWRITING %s FROM %d TO %d",
				       to_list[j]->name, i, j);
				pairfree(&to_list[j]);
				to_list[j] = from_list[i];
				from_list[i] = NULL;
				edited[j] = TRUE;
				break;
			}

			/*
			 *	Add the attribute only if it does not
			 *	exist... but it exists, so we stop
			 *	looking.
			 */
			if (from_list[i]->operator == T_OP_EQ) {
				found = TRUE;
				break;
			}

			/*
			 *	Delete every attribute, independent
			 *	of its value.
			 */
			if (from_list[i]->operator == T_OP_CMP_FALSE) {
				goto delete;
			}

			/*
			 *	Delete all matching attributes from
			 *	"to"
			 */
			if ((from_list[i]->operator == T_OP_SUB) ||
			    (from_list[i]->operator == T_OP_CMP_EQ) ||
			    (from_list[i]->operator == T_OP_LE) ||
			    (from_list[i]->operator == T_OP_GE)) {
				int rcode;
				int old_op = from_list[i]->operator;

				/*
				 *	Check for equality.
				 */
				from_list[i]->operator = T_OP_CMP_EQ;

				/*
				 *	If equal, delete the one in
				 *	the "to" list.
				 */
				rcode = radius_compare_vps(NULL, from_list[i],
							   to_list[j]);
				/*
				 *	We may want to do more
				 *	subtractions, so we re-set the
				 *	operator back to it's original
				 *	value.
				 */
				from_list[i]->operator = old_op;

				switch (old_op) {
				case T_OP_CMP_EQ:
					if (rcode != 0) goto delete;
					break;

				case T_OP_SUB:
					if (rcode == 0) {
					delete:
						RDEBUG4("::: DELETING %s FROM %d TO %d",
						       from_list[i]->name, i, j);
						pairfree(&to_list[j]);
						to_list[j] = NULL;
					}
					break;

					/*
					 *	Enforce <=.  If it's
					 *	>, replace it.
					 */
				case T_OP_LE:
					if (rcode > 0) {
						RDEBUG4("::: REPLACING %s FROM %d TO %d",
						       from_list[i]->name, i, j);
						pairfree(&to_list[j]);
						to_list[j] = from_list[i];
						from_list[i] = NULL;
						edited[j] = TRUE;
					}
					break;

				case T_OP_GE:
					if (rcode < 0) {
						RDEBUG4("::: REPLACING %s FROM %d TO %d",
						       from_list[i]->name, i, j);
						pairfree(&to_list[j]);
						to_list[j] = from_list[i];
						from_list[i] = NULL;
						edited[j] = TRUE;
					}
					break;
				}

				continue;
			}

			rad_assert(0 == 1); /* panic! */
		}
Esempio n. 5
0
/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
 *
 * Takes a single value_pair_map_t, resolves request and list identifiers
 * to pointers in the current request, then attempts to retrieve module
 * specific value(s) using callback, and adds the resulting values to the
 * correct request/list.
 *
 * @param request The current request.
 * @param map specifying destination attribute and location and src identifier.
 * @param func to retrieve module specific values and convert them to
 *	VALUE_PAIRS.
 * @param ctx to be passed to func.
 * @param src name to be used in debugging if different from map value.
 * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
 */
int radius_map2request(REQUEST *request, value_pair_map_t const *map,
		       UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
{
	int rcode, num;
	VALUE_PAIR **list, *vp, *head = NULL;
	REQUEST *context;
	TALLOC_CTX *parent;
	vp_cursor_t cursor;

	/*
	 *	Sanity check inputs.  We can have a list or attribute
	 *	as a destination.
	 */
	if ((map->dst->type != VPT_TYPE_LIST) &&
	    (map->dst->type != VPT_TYPE_ATTR)) {
		REDEBUG("Invalid mapping destination");
		return -2;
	}

	context = request;
	if (radius_request(&context, map->dst->request) < 0) {
		REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
		return -2;
	}

	/*
	 *	If there's no CoA packet and we're updating it,
	 *	auto-allocate it.
	 */
	if (((map->dst->list == PAIR_LIST_COA) ||
	     (map->dst->list == PAIR_LIST_DM)) &&
	    !request->coa) {
		request_alloc_coa(context);
		if (map->dst->list == PAIR_LIST_COA) {
			context->coa->proxy->code = PW_CODE_COA_REQUEST;
		} else {
			context->coa->proxy->code = PW_CODE_DISCONNECT_REQUEST;
		}
	}

	list = radius_list(context, map->dst->list);
	if (!list) {
		REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);

		return -2;
	}

	parent = radius_list_ctx(context, map->dst->list);

	/*
	 *	The callback should either return -1 to signify operations error, -2 when it can't find the
	 *	attribute or list being referenced, or 0 to signify success.
	 *	It may return "sucess", but still have no VPs to work with.
	 */
	rcode = func(&head, request, map, ctx);
	if (rcode < 0) {
		rad_assert(!head);
		return rcode;
	}

	if (!head) return 0;

	/*
	 *	Reparent the VP
	 */
	for (vp = fr_cursor_init(&cursor, &head); vp; vp = fr_cursor_next(&cursor)) {

		VERIFY_VP(vp);
		if (debug_flag) debug_map(request, map, vp);

		(void) talloc_steal(parent, vp);
	}

	/*
	 *	List to list copies.
	 */
	if (map->dst->type == VPT_TYPE_LIST) {
		switch (map->op) {
		case T_OP_CMP_FALSE:
			rad_assert(head == NULL);
			pairfree(list);

			if (map->dst->list == PAIR_LIST_REQUEST) {
				context->username = NULL;
				context->password = NULL;
			}
			break;

		case T_OP_SET:
			if (map->src->type == VPT_TYPE_LIST) {
				pairfree(list);
				*list = head;
			} else {
		case T_OP_EQ:

				rad_assert(map->src->type == VPT_TYPE_EXEC);
				pairmove(parent, list, &head);
				pairfree(&head);
			}

			if (map->dst->list == PAIR_LIST_REQUEST) {
				context->username = pairfind(head, PW_USER_NAME, 0, TAG_ANY);
				context->password = pairfind(head, PW_USER_PASSWORD, 0, TAG_ANY);
			}
			break;

		case T_OP_ADD:
			pairadd(list, head);
			break;

		default:
			pairfree(&head);
			return -1;
		}

		return 0;
	}

	/*
	 *	We now should have only one destination attribute, and
	 *	only one source attribute.
	 */
	rad_assert(head->next == NULL);

	/*
	 *	Find the destination attribute.  We leave with either
	 *	the cursor and vp pointing to the attribute, or vp is
	 *	NULL.
	 */
	num = map->dst->num;
	for (vp = fr_cursor_init(&cursor, list);
	     vp != NULL;
	     vp = fr_cursor_next(&cursor)) {
		VERIFY_VP(vp);
		if ((vp->da == map->dst->da) && (!vp->da->flags.has_tag || (map->dst->tag == TAG_ANY) || (vp->tag == map->dst->tag))) {
			if (num == 0) break;
			num--;
		}
	}

	/*
	 *	Figure out what to do with the source attribute.
	 */
	switch (map->op) {
	case T_OP_CMP_FALSE:	/* remove matching attributes */
		pairfree(&head);
		if (!vp) return 0;

		/*
		 *	Wildcard: delete all of the matching ones,
		 *	based on tag.
		 */
		if (!map->dst->num) {
			pairdelete(list, map->dst->da->attr, map->dst->da->vendor,
				   map->dst->tag);
			vp = NULL;
		} else {
			/*
			 *	We've found the Nth one.  Delete it, and only
			 *	it.
			 */
			vp = fr_cursor_remove(&cursor);
		}

		/*
		 *	Check that the User-Name and User-Password
		 *	caches point to the correct attribute.
		 */
	fixup:
		if (map->dst->list == PAIR_LIST_REQUEST) {
			context->username = pairfind(*list, PW_USER_NAME, 0, TAG_ANY);
			context->password = pairfind(*list, PW_USER_PASSWORD, 0, TAG_ANY);
		}
		pairfree(&vp);
		return 0;

	case T_OP_EQ:		/* set only if not already set */
		if (vp) {
			pairfree(&head);
			return 0;
		}
		fr_cursor_insert(&cursor, head);
		goto fixup;

	case T_OP_SET:		/* over-write if existing, or else add */
		if (vp) vp = fr_cursor_remove(&cursor);
		fr_cursor_insert(&cursor, head);
		goto fixup;

	case T_OP_ADD:		/* append no matter what */
		vp = NULL;
		pairadd(list, head);
		goto fixup;

	case T_OP_SUB:		/* delete if it matches */
		head->op = T_OP_CMP_EQ;
		rcode = radius_compare_vps(NULL, head, vp);
		pairfree(&head);

		if (rcode == 0) {
			vp = fr_cursor_remove(&cursor);
			goto fixup;
		}
		return 0;

	default:		/* filtering operators */
		/*
		 *	If the VP doesn't exist, the filters will add
		 *	it with the given value.
		 */
		if (!vp) {
			fr_cursor_insert(&cursor, head);
			goto fixup;
		}
		break;
	}

	/*
	 *	The LHS exists.  We need to limit it's value based on
	 *	the operator, and the value of the RHS.
	 */
	head->op = map->op;
	rcode = radius_compare_vps(NULL, head, vp);
	head->op = T_OP_SET;

	switch (map->op) {
	case T_OP_CMP_EQ:
		if (rcode == 0) {
	leave:
			pairfree(&head);
			break;
		}
	replace:
		vp = fr_cursor_remove(&cursor);
		fr_cursor_insert(&cursor, head);
		goto fixup;

	case T_OP_LE:
		if (rcode <= 0) goto leave;
		goto replace;

	case T_OP_GE:
		if (rcode >= 0) goto leave;
		goto replace;

	default:
		pairfree(&head);
		return -1;
	}

	return 0;
}