コード例 #1
0
ファイル: rlm_perl.c プロジェクト: xunmengdeganjue/workTest
/*
 *
 *     Verify that a Perl SV is a string and save it in FreeRadius
 *     Value Pair Format
 *
 */
static int pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
		      const char *hash_name, const char *list_name)
{
	char		*val;
	VALUE_PAIR      *vp;

	if (SvOK(sv)) {
		STRLEN len;
		val = SvPV(sv, len);
		vp = fr_pair_make(ctx, vps, key, NULL, op);
		if (!vp) {
		fail:
			REDEBUG("Failed to create pair %s:%s %s %s", list_name, key,
				fr_int2str(fr_tokens, op, "<INVALID>"), val);
			return -1;
		}

		switch (vp->da->type) {
		case PW_TYPE_STRING:
			fr_pair_value_bstrncpy(vp, val, len);
			break;

		default:
			if (fr_pair_value_from_str(vp, val, len) < 0) goto fail;
		}

		RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"),
		       hash_name, key, val);
		return 0;
	}
	return -1;
}
コード例 #2
0
/** Converts a string value into a #VALUE_PAIR
 *
 * @param[in,out] ctx to allocate #VALUE_PAIR (s).
 * @param[out] out where to write the resulting #VALUE_PAIR.
 * @param[in] request The current request.
 * @param[in] map to process.
 * @param[in] uctx The value to parse.
 * @return
 *	- 0 on success.
 *	- -1 on failure.
 */
static int _sql_map_proc_get_value(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
{
	VALUE_PAIR	*vp;
	char const	*value = uctx;

	vp = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
	/*
	 *	Buffer not always talloced, sometimes it's
	 *	just a pointer to a field in a result struct.
	 */
	if (fr_pair_value_from_str(vp, value, strlen(value)) < 0) {
		char *escaped;

		escaped = fr_asprint(vp, value, talloc_array_length(value), '"');
		REDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped,
			map->lhs->tmpl_da->name, fr_strerror());
		talloc_free(vp);

		return -1;
	}

	vp->op = map->op;
	*out = vp;

	return 0;
}
コード例 #3
0
ファイル: rlm_client.c プロジェクト: geaaru/freeradius-server
static int _map_proc_client_get_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request,
				   vp_map_t const *map, void *uctx)
{
	client_get_vp_ctx_t	*client = uctx;
	VALUE_PAIR		*head = NULL, *vp;
	fr_cursor_t		cursor;
	fr_dict_attr_t const	*da;
	CONF_PAIR const		*cp;

	rad_assert(ctx != NULL);

	fr_cursor_init(&cursor, &head);

	/*
	 *	FIXME: allow multiple entries.
	 */
	if (map->lhs->type == TMPL_TYPE_ATTR) {
		da = map->lhs->tmpl_da;
	} else {
		char *attr;

		if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) {
			RWDEBUG("Failed expanding string");
			return -1;
		}

		da = fr_dict_attr_by_name(request->dict, attr);
		if (!da) {
			RWDEBUG("No such attribute '%s'", attr);
			return -1;
		}

		talloc_free(attr);
	}

	for (cp = client->cp;
	     cp;
	     cp = cf_pair_find_next(client->cs, cp, client->field)) {
		char const *value = cf_pair_value(cp);

		MEM(vp = fr_pair_afrom_da(ctx, da));
		if (fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, '\0', false) < 0) {
			RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue(value),
				map->lhs->tmpl_da->name, fr_strerror());
			fr_pair_list_free(&head);
			talloc_free(vp);
			return -1;
		}

		vp->op = map->op;
		fr_cursor_append(&cursor, vp);

		if (map->op != T_OP_ADD) break;	/* Create multiple attribute for multiple CONF_PAIRs */
	}

	*out = head;

	return 0;
}
コード例 #4
0
ファイル: paircmp.c プロジェクト: zi0r/freeradius-server
/*
 *	Generic comparisons, via xlat.
 */
static int generic_cmp(UNUSED void *instance,
		       REQUEST *request,
		       VALUE_PAIR *req,
		       VALUE_PAIR *check,
		       UNUSED VALUE_PAIR *check_list,
		       UNUSED VALUE_PAIR **reply_list)
{
	VP_VERIFY(check);

	if ((check->op != T_OP_REG_EQ) && (check->op != T_OP_REG_NE)) {
		int rcode;
		char name[1024];
		char value[1024];
		VALUE_PAIR *vp;

		snprintf(name, sizeof(name), "%%{%s}", check->da->name);

		if (xlat_eval(value, sizeof(value), request, name, NULL, NULL) < 0) return 0;

		vp = fr_pair_afrom_da(req, check->da);
		vp->op = check->op;
		fr_pair_value_from_str(vp, value, -1, '"', false);

		/*
		 *	Paircmp returns 0 for failed comparison, 1 for succeeded -1 for error.
		 */
		rcode = fr_pair_cmp(check, vp);

		/*
		 *	We're being called from paircmp_func,
		 *	which wants 0 for success, and 1 for fail (sigh)
		 *
		 *	We should really fix the API so that it is
		 *	consistent.  i.e. the comparison callbacks should
		 *	return ONLY the resut of comparing A to B.
		 *	The radius_callback_cmp function should then
		 *	take care of using the operator to see if the
		 *	condition (A OP B) is true or not.
		 *
		 *	This would also allow "<", etc. to work in the
		 *	callback functions...
		 *
		 *	See rlm_ldap, ...groupcmp() for something that
		 *	returns 0 for matched, and 1 for didn't match.
		 */
		rcode = !rcode;
		fr_pair_list_free(&vp);

		return rcode;
	}

	/*
	 *	Will do the xlat for us
	 */
	return paircmp_pairs(request, check, NULL);
}
コード例 #5
0
ファイル: rlm_csv.c プロジェクト: mcnewton/freeradius-server
/*
 *	Convert field X to a VP.
 */
static int csv_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
{
	char const		*str = uctx;
	VALUE_PAIR		*head = NULL, *vp;
	fr_cursor_t		cursor;
	fr_dict_attr_t		const *da;

	rad_assert(ctx != NULL);
	fr_cursor_init(&cursor, &head);

	/*
	 *	FIXME: allow multiple entries.
	 */
	if (map->lhs->type == TMPL_TYPE_ATTR) {
		da = map->lhs->tmpl_da;

	} else {
		char *attr;

		if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) {
			RWDEBUG("Failed expanding string");
			return -1;
		}


		da = fr_dict_attr_by_name(request->dict, attr);
		if (!da) {
			RWDEBUG("No such attribute '%s'", attr);
			return -1;
		}

		talloc_free(attr);
	}

	vp = fr_pair_afrom_da(ctx, da);
	rad_assert(vp);

	if (fr_pair_value_from_str(vp, str, talloc_array_length(str) - 1, '\0', true) < 0) {
		RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue_buffer(str),
			map->lhs->tmpl_da->name, fr_strerror());
		talloc_free(vp);

		return -1;
	}

	vp->op = map->op;
	fr_cursor_append(&cursor, vp);

	*out = head;
	return 0;
}
コード例 #6
0
ファイル: session.c プロジェクト: alagoutte/freeradius-server
static inline VALUE_PAIR *tls_session_cert_attr_add(TALLOC_CTX *ctx, REQUEST *request, fr_cursor_t *cursor,
					    	    int attr, int attr_index, char const *value)
{
	VALUE_PAIR *vp;
	fr_dict_attr_t const *da = *(cert_attr_names[attr][attr_index]);

	MEM(vp = fr_pair_afrom_da(ctx, da));
	if (value) {
		if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
			RPWDEBUG("Failed creating attribute %s", da->name);
			talloc_free(vp);
			return NULL;
		}
	}
	RINDENT();
	RDEBUG3("%pP", vp);
	REXDENT();
	fr_cursor_append(cursor, vp);

	return vp;
}
コード例 #7
0
ファイル: rlm_perl.c プロジェクト: geaaru/freeradius-server
/*
 *
 *     Verify that a Perl SV is a string and save it in FreeRadius
 *     Value Pair Format
 *
 */
static int pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
		      const char *hash_name, const char *list_name)
{
	char		*val;
	VALUE_PAIR      *vp;
	STRLEN		len;

	if (!SvOK(sv)) return -1;

	val = SvPV(sv, len);
	vp = fr_pair_make(ctx, request->dict, vps, key, NULL, op);
	if (!vp) {
	fail:
		REDEBUG("Failed to create pair %s:%s %s %s", list_name, key,
			fr_int2str(fr_tokens_table, op, "<INVALID>"), val);
		return -1;
	}

	switch (vp->vp_type) {
	case FR_TYPE_STRING:
		fr_pair_value_bstrncpy(vp, val, len);
		break;

	case FR_TYPE_OCTETS:
		fr_pair_value_memcpy(vp, (uint8_t const *)val, len);
		break;

	default:
		if (fr_pair_value_from_str(vp, val, len, '\0', false) < 0) goto fail;
	}

	VP_VERIFY(vp);

	RDEBUG2("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens_table, op, "<INVALID>"),
	        hash_name, key, val);
	return 0;
}
コード例 #8
0
ファイル: rlm_perl.c プロジェクト: janetuk/freeradius
/*
 *
 *     Verify that a Perl SV is a string and save it in FreeRadius
 *     Value Pair Format
 *
 */
static void pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
		      const char *hash_name, const char *list_name)
{
	char		*val = NULL;
	VALUE_PAIR      *vp;
	STRLEN len;

	if (!SvOK(sv)) {
		REDEBUG("Internal failure creating pair &%s:%s %s $%s{'%s'} -> '%s'", list_name, key,
			fr_int2str(fr_tokens, op, "<INVALID>"), hash_name, key, (val ? val : "undef"));
		return;
	}

	val = SvPV(sv, len);
	vp = fr_pair_make(ctx, vps, key, NULL, op);
	if (!vp) {
	fail:
		REDEBUG("Failed to create pair - %s", fr_strerror());
		REDEBUG("    &%s:%s %s $%s{'%s'} -> '%s'", list_name, key,
			fr_int2str(fr_tokens, op, "<INVALID>"), hash_name, key, (val ? val : "undef"));
		return;
	}

	switch (vp->da->type) {
	case PW_TYPE_STRING:
		fr_pair_value_bstrncpy(vp, val, len);
		break;

	default:
		VERIFY_VP(vp);

		if (fr_pair_value_from_str(vp, val, len) < 0) goto fail;
	}

	RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"),
	       hash_name, key, val);
}
コード例 #9
0
/** Builds attribute representing OID string and adds 'index' attributes where required
 *
 * Will convert an OID string in the format @verbatim .1.2.3.4.5.0 @endverbatim
 * into a pair with a #fr_dict_attr_t of the dictionary attribute matching the OID
 * string, as evaluated from the specified parent.
 *
 * If an OID component does not match a child of a previous OID component, but a child
 * with attribute number 0 exists, and a child with attribute number 1 also exists,
 * the child with attribute number 0 will be used as an 'index' pair, and will be
 * created with the value of the non matching OID component.
 *
 * Parsing will then resume using the child with attribute number 1.
 *
 * This allows traversals of SNMP tables to be represented by the sequence of pairs
 * and allows the full range of entry indexes which would not be possible if we represented
 * table index numbers as TLV attributes.
 *
 * @param[in] ctx	to allocate new pairs in.
 * @param[in] conf	radsnmp config.
 * @param[in] cursor	to add pairs to.
 * @param[in] oid	string to evaluate.
 * @param[in] type	SNMP value type.
 * @param[in] value	to assign to OID attribute (SET operations only).
 * @return
 *	- >0 on success (how much of the OID string we parsed).
 *	- <=0 on failure (where format error occurred).
 */
static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, radsnmp_conf_t *conf, fr_cursor_t *cursor,
				     char const *oid, int type, char const *value)
{
	ssize_t			slen;
	char const		*p = oid;
	unsigned int		attr;
	fr_dict_attr_t const	*index_attr, *da;
	fr_dict_attr_t const	*parent = conf->snmp_root;
	VALUE_PAIR		*vp;
	int			ret;

	if (!oid) return 0;

	fr_cursor_tail(cursor);

	/*
	 *	Trim first.
	 */
	if (p[0] == '.') p++;

	/*
	 *	Support for indexes.  If we can't find an attribute
	 *	matching a child at a given level in the OID tree,
	 *	look for attribute 0 (type integer) at that level.
	 *	We use this to represent the index instead.
	 */
	for (;;) {
		unsigned int num = 0;

		slen = fr_dict_attr_by_oid(conf->dict, &parent, &attr, p);
		if (slen > 0) break;
		p += -(slen);

		if (fr_dict_oid_component(&num, &p) < 0) break;	/* Just advances the pointer */
		assert(attr == num);
		p++;

		/*
		 *	Check for an index attribute
		 */
		index_attr = fr_dict_attr_child_by_num(parent, 0);
		if (!index_attr) {
			fr_strerror_printf("Unknown OID component: No index attribute at this level");
			break;
		}

		if (index_attr->type != FR_TYPE_UINT32) {
			fr_strerror_printf("Index is not a \"integer\"");
			break;
		}

		/*
		 *	By convention SNMP entries are at .1
		 */
		parent = fr_dict_attr_child_by_num(parent, 1);
		if (!parent) {
			fr_strerror_printf("Unknown OID component: No entry attribute at this level");
			break;
		}

		/*
		 *	Entry must be a TLV type
		 */
		if (parent->type != FR_TYPE_TLV) {
			fr_strerror_printf("Entry is not \"tlv\"");
			break;
		}

		/*
		 *	We've skipped over the index attribute, and
		 *	the index number should be available in attr.
		 */
		MEM(vp = fr_pair_afrom_da(ctx, index_attr));
		vp->vp_uint32 = attr;

		fr_cursor_append(cursor, vp);
	}

	/*
	 *	We errored out processing the OID.
	 */
	if (slen <= 0) {
	error:
		fr_cursor_free_list(cursor);
		return slen;
	}

	fr_strerror();	/* Clear pending errors */

	/*
	 *	SNMP requests the leaf under the OID with .0.
	 */
	if (attr != 0) {
		da = fr_dict_attr_child_by_num(parent, attr);
		if (!da) {
			fr_strerror_printf("Unknown leaf attribute %i", attr);
			return -(slen);
		}
	} else {
		da = parent;
	}

	vp = fr_pair_afrom_da(ctx, da);
	if (!vp) {
		fr_strerror_printf("Failed allocating OID attribute");
		return -(slen);
	}

	/*
	 *	VALUE_PAIRs with no value need a 1 byte value buffer.
	 */
	if (!value) {
		switch (da->type) {
		/*
		 *	We can blame the authors of RFC 6929 for
		 *	this hack.  Apparently the presence or absence
		 *	of an attribute isn't considered a useful means
		 *	of conveying information, so empty TLVs are
		 *	disallowed.
		 */
		case FR_TYPE_TLV:
			fr_pair_to_unknown(vp);
			/* FALL-THROUGH */

		case FR_TYPE_OCTETS:
			fr_pair_value_memcpy(vp, (uint8_t const *)"\0", 1, true);
			break;

		case FR_TYPE_STRING:
			fr_pair_value_bstrncpy(vp, "\0", 1);
			break;

		/*
		 *	Fine to leave other values zeroed out.
		 */
		default:
			break;
		}

		fr_cursor_append(cursor, vp);
		return slen;
	}

	if (da->type == FR_TYPE_TLV) {
		fr_strerror_printf("TLVs cannot hold values");
		return -(slen);
	}

	ret = fr_pair_value_from_str(vp, value, strlen(value), '\0', true);
	if (ret < 0) {
		slen = -(slen);
		goto error;
	}

	vp = fr_pair_afrom_da(ctx, attr_freeradius_snmp_type);
	if (!vp) {
		slen = -(slen);
		goto error;
	}
	vp->vp_uint32 = type;

	fr_cursor_append(cursor, vp);

	return slen;
}
コード例 #10
0
/*
 *	Allocate an IP number from the pool.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
	rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
	char allocation[MAX_STRING_LEN];
	int allocation_len;
	VALUE_PAIR *vp;
	rlm_sql_handle_t *handle;
	time_t now;

	/*
	 *	If there is a Framed-IP-Address attribute in the reply do nothing
	 */
	if (fr_pair_find_by_num(request->reply->vps, inst->framed_ip_address, 0, TAG_ANY) != NULL) {
		RDEBUG("Framed-IP-Address already exists");

		return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
	}

	if (fr_pair_find_by_num(request->config, PW_POOL_NAME, 0, TAG_ANY) == NULL) {
		RDEBUG("No Pool-Name defined");

		return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
	}

	handle = fr_connection_get(inst->sql_inst->pool);
	if (!handle) {
		REDEBUG("Failed reserving SQL connection");
		return RLM_MODULE_FAIL;
	}

	if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Limit the number of clears we do.  There are minor
	 *	race conditions for the check, but so what.  The
	 *	actual work is protected by a transaction.  The idea
	 *	here is that if we're allocating 100 IPs a second,
	 *	we're only do 1 CLEAR per second.
	 */
	now = time(NULL);
	if (inst->last_clear < now) {
		inst->last_clear = now;

		DO_PART(allocate_begin);
		DO_PART(allocate_clear);
		DO_PART(allocate_commit);
	}

	DO_PART(allocate_begin);

	allocation_len = sqlippool_query1(allocation, sizeof(allocation),
					  inst->allocate_find, handle,
					  inst, request, (char *) NULL, 0);

	/*
	 *	Nothing found...
	 */
	if (allocation_len == 0) {
		DO_PART(allocate_commit);

		/*
		 *Should we perform pool-check ?
		 */
		if (inst->pool_check && *inst->pool_check) {

			/*
			 *Ok, so the allocate-find query found nothing ...
			 *Let's check if the pool exists at all
			 */
			allocation_len = sqlippool_query1(allocation, sizeof(allocation),
							  inst->pool_check, handle, inst, request,
							  (char *) NULL, 0);

			fr_connection_release(inst->sql_inst->pool, handle);

			if (allocation_len) {

				/*
				 *	Pool exists after all... So,
				 *	the failure to allocate the IP
				 *	address was most likely due to
				 *	the depletion of the pool. In
				 *	that case, we should return
				 *	NOTFOUND
				 */
				RDEBUG("pool appears to be full");
				return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);

			}

			/*
			 *	Pool doesn't exist in the table. It
			 *	may be handled by some other instance of
			 *	sqlippool, so we should just ignore this
			 *	allocation failure and return NOOP
			 */
			RDEBUG("IP address could not be allocated as no pool exists with that name");
			return RLM_MODULE_NOOP;

		}

		fr_connection_release(inst->sql_inst->pool, handle);

		RDEBUG("IP address could not be allocated");
		return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
	}

	/*
	 *	See if we can create the VP from the returned data.  If not,
	 *	error out.  If so, add it to the list.
	 */
	vp = fr_pair_afrom_num(request->reply, inst->framed_ip_address, 0);
	if (fr_pair_value_from_str(vp, allocation, allocation_len) < 0) {
		DO_PART(allocate_commit);

		RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
		fr_connection_release(inst->sql_inst->pool, handle);
		return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
	}

	RDEBUG("Allocated IP %s", allocation);
	fr_pair_add(&request->reply->vps, vp);

	/*
	 *	UPDATE
	 */
	sqlippool_command(inst->allocate_update, &handle, inst, request,
			  allocation, allocation_len);

	DO_PART(allocate_commit);

	fr_connection_release(inst->sql_inst->pool, handle);

	return do_logging(request, inst->log_success, RLM_MODULE_OK);
}
コード例 #11
0
static FR_CODE eap_fast_eap_payload(REQUEST *request, eap_session_t *eap_session,
				    tls_session_t *tls_session, VALUE_PAIR *tlv_eap_payload)
{
	FR_CODE			code = FR_CODE_ACCESS_REJECT;
	rlm_rcode_t		rcode;
	VALUE_PAIR		*vp;
	eap_fast_tunnel_t	*t;
	REQUEST			*fake;

	RDEBUG2("Processing received EAP Payload");

	/*
	 * Allocate a fake REQUEST structure.
	 */
	fake = request_alloc_fake(request, NULL);
	rad_assert(!fake->packet->vps);

	t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);

	/*
	 * Add the tunneled attributes to the fake request.
	 */

	fake->packet->vps = fr_pair_afrom_da(fake->packet, attr_eap_message);
	fr_pair_value_memcpy(fake->packet->vps, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length, false);

	RDEBUG2("Got tunneled request");
	log_request_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);

	/*
	 * Tell the request that it's a fake one.
	 */
	MEM(fr_pair_add_by_da(fake->packet, &vp, &fake->packet->vps, attr_freeradius_proxied_to) >= 0);
	fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1"), '\0', false);

	/*
	 * Update other items in the REQUEST data structure.
	 */
	fake->username = fr_pair_find_by_da(fake->packet->vps, attr_user_name, TAG_ANY);
	fake->password = fr_pair_find_by_da(fake->packet->vps, attr_user_password, TAG_ANY);

	/*
	 * No User-Name, try to create one from stored data.
	 */
	if (!fake->username) {
		/*
		 * No User-Name in the stored data, look for
		 * an EAP-Identity, and pull it out of there.
		 */
		if (!t->username) {
			vp = fr_pair_find_by_da(fake->packet->vps, attr_eap_message, TAG_ANY);
			if (vp &&
			    (vp->vp_length >= EAP_HEADER_LEN + 2) &&
			    (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
				/*
				 * Create & remember a User-Name
				 */
				MEM(t->username = fr_pair_afrom_da(t, attr_user_name));
				t->username->vp_tainted = true;
				fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);

				RDEBUG2("Got tunneled identity of %pV", &t->username->data);
			} else {
				/*
				 * Don't reject the request outright,
				 * as it's permitted to do EAP without
				 * user-name.
				 */
				RWDEBUG2("No EAP-Identity found to start EAP conversation");
			}
		} /* else there WAS a t->username */

		if (t->username) {
			vp = fr_pair_copy(fake->packet, t->username);
			fr_pair_add(&fake->packet->vps, vp);
			fake->username = vp;
		}
	} /* else the request ALREADY had a User-Name */

	if (t->stage == EAP_FAST_AUTHENTICATION) {	/* FIXME do this only for MSCHAPv2 */
		VALUE_PAIR *tvp;

		tvp = fr_pair_afrom_da(fake, attr_eap_type);
		tvp->vp_uint32 = t->default_provisioning_method;
		fr_pair_add(&fake->control, tvp);

		/*
		 * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
		 */
		if (t->mode == EAP_FAST_PROVISIONING_ANON) {
			tvp = fr_pair_afrom_da(fake, attr_ms_chap_challenge);
			fr_pair_value_memcpy(tvp, t->keyblock->server_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, false);
			fr_pair_add(&fake->control, tvp);
			RHEXDUMP(L_DBG_LVL_MAX, t->keyblock->server_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, "MSCHAPv2 auth_challenge");

			tvp = fr_pair_afrom_da(fake, attr_ms_chap_peer_challenge);
			fr_pair_value_memcpy(tvp, t->keyblock->client_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, false);
			fr_pair_add(&fake->control, tvp);
			RHEXDUMP(L_DBG_LVL_MAX, t->keyblock->client_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, "MSCHAPv2 peer_challenge");
		}
	}

	/*
	 * Call authentication recursively, which will
	 * do PAP, CHAP, MS-CHAP, etc.
	 */
	eap_virtual_server(request, fake, eap_session, t->virtual_server);

	/*
	 * Decide what to do with the reply.
	 */
	switch (fake->reply->code) {
	case 0:			/* No reply code, must be proxied... */
#ifdef WITH_PROXY
		vp = fr_pair_find_by_da(fake->control, attr_proxy_to_realm, TAG_ANY);
		if (vp) {
			int			ret;
			eap_tunnel_data_t	*tunnel;

			RDEBUG2("Tunneled authentication will be proxied to %pV", &vp->data);

			/*
			 *	Tell the original request that it's going to be proxied.
			 */
			fr_pair_list_copy_by_da(request, &request->control, fake->control, attr_proxy_to_realm);

			/*
			 *	Seed the proxy packet with the tunneled request.
			 */
			rad_assert(!request->proxy);

			/*
			 *	FIXME: Actually proxy stuff
			 */
			request->proxy = request_alloc_fake(request, NULL);

			request->proxy->packet = talloc_steal(request->proxy, fake->packet);
			memset(&request->proxy->packet->src_ipaddr, 0,
			       sizeof(request->proxy->packet->src_ipaddr));
			memset(&request->proxy->packet->src_ipaddr, 0,
			       sizeof(request->proxy->packet->src_ipaddr));
			request->proxy->packet->src_port = 0;
			request->proxy->packet->dst_port = 0;
			fake->packet = NULL;
			fr_radius_packet_free(&fake->reply);
			fake->reply = NULL;

			/*
			 *	Set up the callbacks for the tunnel
			 */
			tunnel = talloc_zero(request, eap_tunnel_data_t);
			tunnel->tls_session = tls_session;

			/*
			 *	Associate the callback with the request.
			 */
			ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
					       tunnel, false, false, false);
			fr_cond_assert(ret == 0);

			/*
			 *	rlm_eap.c has taken care of associating the eap_session
			 *	with the fake request.
			 *
			 *	So we associate the fake request with this request.
			 */
			ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
					       fake, true, false, false);
			fr_cond_assert(ret == 0);

			fake = NULL;

			/*
			 *	Didn't authenticate the packet, but we're proxying it.
			 */
			code = FR_CODE_STATUS_CLIENT;

		} else
#endif	/* WITH_PROXY */
		  {
			  REDEBUG("No tunneled reply was found, and the request was not proxied: rejecting the user");
			  code = FR_CODE_ACCESS_REJECT;
		  }
		break;

	default:
		/*
		 *	Returns RLM_MODULE_FOO, and we want to return FR_FOO
		 */
		rcode = process_reply(eap_session, tls_session, request, fake->reply);
		switch (rcode) {
		case RLM_MODULE_REJECT:
			code = FR_CODE_ACCESS_REJECT;
			break;

		case RLM_MODULE_HANDLED:
			code = FR_CODE_ACCESS_CHALLENGE;
			break;

		case RLM_MODULE_OK:
			code = FR_CODE_ACCESS_ACCEPT;
			break;

		default:
			code = FR_CODE_ACCESS_REJECT;
			break;
		}
		break;
	}

	talloc_free(fake);

	return code;
}
コード例 #12
0
ファイル: sql.c プロジェクト: xunmengdeganjue/workTest
/*************************************************************************
 *
 *	Function: sql_fr_pair_list_afrom_str
 *
 *	Purpose: Read entries from the database and fill VALUE_PAIR structures
 *
 *************************************************************************/
int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_row_t row)
{
	VALUE_PAIR *vp;
	char const *ptr, *value;
	char buf[MAX_STRING_LEN];
	char do_xlat = 0;
	FR_TOKEN token, op = T_EOL;

	/*
	 *	Verify the 'Attribute' field
	 */
	if (!row[2] || row[2][0] == '\0') {
		REDEBUG("Attribute field is empty or NULL, skipping the entire row");
		return -1;
	}

	/*
	 *	Verify the 'op' field
	 */
	if (row[4] != NULL && row[4][0] != '\0') {
		ptr = row[4];
		op = gettoken(&ptr, buf, sizeof(buf), false);
		if (!fr_assignment_op[op] && !fr_equality_op[op]) {
			REDEBUG("Invalid op \"%s\" for attribute %s", row[4], row[2]);
			return -1;
		}

	} else {
		/*
		 *  Complain about empty or invalid 'op' field
		 */
		op = T_OP_CMP_EQ;
		REDEBUG("The op field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
		REDEBUG("You MUST FIX THIS if you want the configuration to behave as you expect");
	}

	/*
	 *	The 'Value' field may be empty or NULL
	 */
	if (!row[3]) {
		REDEBUG("Value field is empty or NULL, skipping the entire row");
		return -1;
	}

	value = row[3];

	/*
	 *	If we have a new-style quoted string, where the
	 *	*entire* string is quoted, do xlat's.
	 */
	if (row[3] != NULL &&
	   ((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) &&
	   (row[3][0] == row[3][strlen(row[3])-1])) {

		token = gettoken(&value, buf, sizeof(buf), false);
		switch (token) {
		/*
		 *	Take the unquoted string.
		 */
		case T_SINGLE_QUOTED_STRING:
		case T_DOUBLE_QUOTED_STRING:
			value = buf;
			break;

		/*
		 *	Mark the pair to be allocated later.
		 */
		case T_BACK_QUOTED_STRING:
			do_xlat = 1;

			/* FALL-THROUGH */

		/*
		 *	Keep the original string.
		 */
		default:
			value = row[3];
			break;
		}
	}

	/*
	 *	Create the pair
	 */
	vp = fr_pair_make(ctx, NULL, row[2], NULL, op);
	if (!vp) {
		REDEBUG("Failed to create the pair: %s", fr_strerror());
		return -1;
	}

	if (do_xlat) {
		if (fr_pair_mark_xlat(vp, value) < 0) {
			REDEBUG("Error marking pair for xlat: %s", fr_strerror());

			talloc_free(vp);
			return -1;
		}
	} else {
		if (fr_pair_value_from_str(vp, value, -1) < 0) {
			REDEBUG("Error parsing value: %s", fr_strerror());

			talloc_free(vp);
			return -1;
		}
	}

	/*
	 *	Add the pair into the packet
	 */
	fr_pair_add(head, vp);
	return 0;
}
コード例 #13
0
ファイル: session.c プロジェクト: alagoutte/freeradius-server
/** Extract attributes from an X509 certificate
 *
 * @param cursor	to copy attributes to.
 * @param ctx		to allocate attributes in.
 * @param session	current TLS session.
 * @param cert		to validate.
 * @param depth		the certificate is in the certificate chain (0 == leaf).
 * @return
 *	- 0 on success.
 *	- < 0 on failure.
 */
int tls_session_pairs_from_x509_cert(fr_cursor_t *cursor, TALLOC_CTX *ctx,
				     tls_session_t *session, X509 *cert, int depth)
{
	char		buffer[1024];
	char		attribute[256];
	char		**identity;
	int		attr_index, loc;

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
	STACK_OF(X509_EXTENSION) const *ext_list = NULL;
#else
	STACK_OF(X509_EXTENSION) *ext_list = NULL;
#endif

	ASN1_INTEGER	*sn = NULL;
	ASN1_TIME	*asn_time = NULL;

	VALUE_PAIR	*vp = NULL;

	REQUEST		*request;

#define CERT_ATTR_ADD(_attr, _attr_index, _value) tls_session_cert_attr_add(ctx, request, cursor, _attr, _attr_index, _value)

	attr_index = depth;
	if (attr_index > 1) attr_index = 1;

	request = (REQUEST *)SSL_get_ex_data(session->ssl, FR_TLS_EX_INDEX_REQUEST);
	rad_assert(request != NULL);

	identity = (char **)SSL_get_ex_data(session->ssl, FR_TLS_EX_INDEX_IDENTITY);

	if (RDEBUG_ENABLED3) {
		buffer[0] = '\0';
		X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
		buffer[sizeof(buffer) - 1] = '\0';
		RDEBUG3("Creating attributes for \"%s\":", buffer[0] ? buffer : "Cert missing subject OID");
	}

	/*
	 *	Get the Serial Number
	 */
	sn = X509_get_serialNumber(cert);
	if (sn && ((size_t) sn->length < (sizeof(buffer) / 2))) {
		char *p = buffer;
		int i;

		for (i = 0; i < sn->length; i++) {
			sprintf(p, "%02x", (unsigned int)sn->data[i]);
			p += 2;
		}

		CERT_ATTR_ADD(IDX_SERIAL, attr_index, buffer);
	}

	/*
	 *	Get the Expiration Date
	 */
	buffer[0] = '\0';
	asn_time = X509_get_notAfter(cert);
	if (identity && asn_time && (asn_time->length < (int)sizeof(buffer))) {
		time_t expires;

		/*
		 *	Add expiration as a time since the epoch
		 */
		if (tls_utils_asn1time_to_epoch(&expires, asn_time) < 0) {
			RPWDEBUG("Failed parsing certificate expiry time");
		} else {
			vp = CERT_ATTR_ADD(IDX_EXPIRATION, attr_index, NULL);
			vp->vp_date = expires;
		}
	}

	/*
	 *	Get the Subject & Issuer
	 */
	buffer[0] = '\0';
	X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer));
	buffer[sizeof(buffer) - 1] = '\0';
	if (identity && buffer[0]) {
		CERT_ATTR_ADD(IDX_SUBJECT, attr_index, buffer);

		/*
		 *	Get the Common Name, if there is a subject.
		 */
		X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
					  NID_commonName, buffer, sizeof(buffer));
		buffer[sizeof(buffer) - 1] = '\0';

		if (buffer[0]) {
			CERT_ATTR_ADD(IDX_COMMON_NAME, attr_index, buffer);
		}
	}

	X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer));
	buffer[sizeof(buffer) - 1] = '\0';
	if (identity && buffer[0]) {
		CERT_ATTR_ADD(IDX_ISSUER, attr_index, buffer);
	}

	/*
	 *	Get the RFC822 Subject Alternative Name
	 */
	loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, 0);
	if (loc >= 0) {
		X509_EXTENSION	*ext = NULL;
		GENERAL_NAMES	*names = NULL;
		int		i;

		ext = X509_get_ext(cert, loc);
		if (ext && (names = X509V3_EXT_d2i(ext))) {
			for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
				GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);

				switch (name->type) {
#ifdef GEN_EMAIL
				case GEN_EMAIL: {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
					char const *rfc822Name = (char const *)ASN1_STRING_get0_data(name->d.rfc822Name);
#else
					char *rfc822Name = (char *)ASN1_STRING_data(name->d.rfc822Name);
#endif

					CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_EMAIL, attr_index, rfc822Name);
					break;
				}
#endif	/* GEN_EMAIL */
#ifdef GEN_DNS
				case GEN_DNS: {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
					char const *dNSName = (char const *)ASN1_STRING_get0_data(name->d.dNSName);
#else
					char *dNSName = (char *)ASN1_STRING_data(name->d.dNSName);
#endif
					CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_DNS, attr_index, dNSName);
					break;
				}
#endif	/* GEN_DNS */
#ifdef GEN_OTHERNAME
				case GEN_OTHERNAME:
					/* look for a MS UPN */
					if (NID_ms_upn != OBJ_obj2nid(name->d.otherName->type_id)) break;

					/* we've got a UPN - Must be ASN1-encoded UTF8 string */
					if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
						CERT_ATTR_ADD(IDX_SUBJECT_ALT_NAME_UPN, attr_index,
								  (char *)name->d.otherName->value->value.utf8string);
						break;
					}

					RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)");
					break;
#endif	/* GEN_OTHERNAME */
				default:
					/* XXX TODO handle other SAN types */
					break;
				}
			}
		}
		if (names != NULL) GENERAL_NAMES_free(names);
	}

	/*
	 *	Only add extensions for the actual client certificate
	 */
	if (attr_index == 0) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
		ext_list = X509_get0_extensions(cert);
#else
		ext_list = cert->cert_info->extensions;
#endif

		/*
		 *	Grab the X509 extensions, and create attributes out of them.
		 *	For laziness, we re-use the OpenSSL names
		 */
		if (sk_X509_EXTENSION_num(ext_list) > 0) {
			int i, len;
			char *p;
			BIO *out;

			out = BIO_new(BIO_s_mem());
			strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));

			for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
				char			value[1024];
				ASN1_OBJECT		*obj;
				X509_EXTENSION		*ext;
				fr_dict_attr_t const	*da;

				ext = sk_X509_EXTENSION_value(ext_list, i);

				obj = X509_EXTENSION_get_object(ext);
				i2a_ASN1_OBJECT(out, obj);

				len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
				if (len <= 0) continue;

				attribute[16 + len] = '\0';

				for (p = attribute + 16; *p != '\0'; p++) if (*p == ' ') *p = '-';

				X509V3_EXT_print(out, ext, 0, 0);
				len = BIO_read(out, value , sizeof(value) - 1);
				if (len <= 0) continue;

				value[len] = '\0';

				da = fr_dict_attr_by_name(dict_freeradius, attribute);
				if (!da) {
					RWDEBUG3("Skipping attribute %s: "
						 "Add dictionary definition if you want to access it", attribute);
					continue;
				}

				MEM(vp = fr_pair_afrom_da(request, da));
				if (fr_pair_value_from_str(vp, value, -1, '\0', true) < 0) {
					RPWDEBUG3("Skipping: %s += '%s'", attribute, value);
					talloc_free(vp);
					continue;
				}

				fr_cursor_append(cursor, vp);
			}
			BIO_free_all(out);
		}
	}

	return 0;
}
コード例 #14
0
ファイル: session.c プロジェクト: alagoutte/freeradius-server
/** Determine the PSK to use for an incoming connection
 *
 * @param[in] ssl		session.
 * @param[in] identity		The identity of the PSK to search for.
 * @param[out] psk		Where to write the PSK we found (if any).
 * @param[in] max_psk_len	The length of the buffer provided for PSK.
 * @return
 *	- 0 if no PSK matching identity was found.
 *	- >0 if a PSK matching identity was found (the length of bytes written to psk).
 */
unsigned int tls_session_psk_server_cb(SSL *ssl, const char *identity,
				       unsigned char *psk, unsigned int max_psk_len)
{
	unsigned int	psk_len = 0;
	fr_tls_conf_t	*conf;
	REQUEST		*request;

	conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
	if (!conf) return 0;

	request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
	if (request && conf->psk_query) {
		size_t hex_len;
		VALUE_PAIR *vp;
		char buffer[2 * PSK_MAX_PSK_LEN + 4]; /* allow for too-long keys */

		/*
		 *	The passed identity is weird.  Deny it.
		 */
		if (!session_psk_identity_is_safe(identity)) {
			RWDEBUG("Invalid characters in PSK identity %s", identity);
			return 0;
		}

		MEM(pair_update_request(&vp, attr_tls_psk_identity) >= 0);
		if (fr_pair_value_from_str(vp, identity, -1, '\0', true) < 0) {
			RPWDEBUG2("Failed parsing TLS PSK Identity");
			talloc_free(vp);
			return 0;
		}

		hex_len = xlat_eval(buffer, sizeof(buffer), request, conf->psk_query, NULL, NULL);
		if (!hex_len) {
			RWDEBUG("PSK expansion returned an empty string.");
			return 0;
		}

		/*
		 *	The returned key is truncated at MORE than
		 *	OpenSSL can handle.  That way we can detect
		 *	the truncation, and complain about it.
		 */
		if (hex_len > (2 * max_psk_len)) {
			RWDEBUG("Returned PSK is too long (%u > %u)", (unsigned int) hex_len, 2 * max_psk_len);
			return 0;
		}

		/*
		 *	Leave the TLS-PSK-Identity in the request, and
		 *	convert the expansion from printable string
		 *	back to hex.
		 */
		return fr_hex2bin(psk, max_psk_len, buffer, hex_len);
	}

	if (!conf->psk_identity) {
		DEBUG("No static PSK identity set.  Rejecting the user");
		return 0;
	}

	/*
	 *	No REQUEST, or no dynamic query.  Just look for a
	 *	static identity.
	 */
	if (strcmp(identity, conf->psk_identity) != 0) {
		ERROR("Supplied PSK identity %s does not match configuration.  Rejecting.",
		      identity);
		return 0;
	}

	psk_len = strlen(conf->psk_password);
	if (psk_len > (2 * max_psk_len)) return 0;

	return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
}
コード例 #15
0
/** Callback for map_to_request
 *
 * Performs exactly the same job as map_to_vp, but pulls attribute values from LDAP entries
 *
 * @see map_to_vp
 */
int rlm_ldap_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
{
	rlm_ldap_result_t *self = uctx;
	VALUE_PAIR *head = NULL, *vp;
	vp_cursor_t cursor;
	int i;

	fr_cursor_init(&cursor, &head);

	switch (map->lhs->type) {
	/*
	 *	This is a mapping in the form of:
	 *		<list>: += <ldap attr>
	 *
	 *	Where <ldap attr> is:
	 *		<list>:<attr> <op> <value>
	 *
	 *	It is to allow for legacy installations which stored
	 *	RADIUS control and reply attributes in separate LDAP
	 *	attributes.
	 */
	case TMPL_TYPE_LIST:
		for (i = 0; i < self->count; i++) {
			vp_map_t *attr = NULL;

			RDEBUG3("Parsing valuepair string \"%s\"", self->values[i]->bv_val);
			if (map_afrom_attr_str(ctx, &attr, self->values[i]->bv_val,
					       map->lhs->tmpl_request, map->lhs->tmpl_list,
					       REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
				RWDEBUG("Failed parsing \"%s\" as valuepair (%s), skipping...", fr_strerror(),
					self->values[i]->bv_val);
				continue;
			}

			if (attr->lhs->tmpl_request != map->lhs->tmpl_request) {
				RWDEBUG("valuepair \"%s\" has conflicting request qualifier (%s vs %s), skipping...",
					self->values[i]->bv_val,
					fr_int2str(request_refs, attr->lhs->tmpl_request, "<INVALID>"),
					fr_int2str(request_refs, map->lhs->tmpl_request, "<INVALID>"));
			next_pair:
				talloc_free(attr);
				continue;
			}

			if ((attr->lhs->tmpl_list != map->lhs->tmpl_list)) {
				RWDEBUG("valuepair \"%s\" has conflicting list qualifier (%s vs %s), skipping...",
					self->values[i]->bv_val,
					fr_int2str(pair_lists, attr->lhs->tmpl_list, "<INVALID>"),
					fr_int2str(pair_lists, map->lhs->tmpl_list, "<INVALID>"));
				goto next_pair;
			}

			if (map_to_vp(request, &vp, request, attr, NULL) < 0) {
				RWDEBUG("Failed creating attribute for valuepair \"%s\", skipping...",
					self->values[i]->bv_val);
				goto next_pair;
			}

			fr_cursor_merge(&cursor, vp);
			talloc_free(attr);

			/*
			 *	Only process the first value, unless the operator is +=
			 */
			if (map->op != T_OP_ADD) break;
		}
		break;

	/*
	 *	Iterate over all the retrieved values,
	 *	don't try and be clever about changing operators
	 *	just use whatever was set in the attribute map.
	 */
	case TMPL_TYPE_ATTR:
		for (i = 0; i < self->count; i++) {
			if (!self->values[i]->bv_len) continue;

			vp = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
			rad_assert(vp);

			if (fr_pair_value_from_str(vp, self->values[i]->bv_val, self->values[i]->bv_len) < 0) {
				char *escaped;

				escaped = fr_asprint(vp, self->values[i]->bv_val, self->values[i]->bv_len, '"');
				RWDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped,
					map->lhs->tmpl_da->name, fr_strerror());

				talloc_free(vp); /* also frees escaped */
				continue;
			}

			vp->op = map->op;
			fr_cursor_insert(&cursor, vp);

			/*
			 *	Only process the first value, unless the operator is +=
			 */
			if (map->op != T_OP_ADD) break;
		}
		break;

	default:
		rad_assert(0);
	}

	*out = head;

	return 0;
}