예제 #1
0
/*
 *	Merge a cached entry into a REQUEST.
 */
static void cache_merge(rlm_cache_t *inst, REQUEST *request,
			rlm_cache_entry_t *c)
{
	VALUE_PAIR *vp;

	rad_assert(request != NULL);
	rad_assert(c != NULL);

	if (c->control) {
		vp = paircopy(c->control);
		pairmove(&request->config_items, &vp);
		pairfree(&vp);
	}

	if (c->request && request->packet) {
		vp = paircopy(c->request);
		pairmove(&request->packet->vps, &vp);
		pairfree(&vp);
	}

	if (c->reply && request->reply) {
		vp = paircopy(c->reply);
		pairmove(&request->reply->vps, &vp);
		pairfree(&vp);
	}
	
	if (inst->stats) {
		vp = paircreate(PW_CACHE_ENTRY_HITS, 0, PW_TYPE_INTEGER);
		rad_assert(vp != NULL);
		
		vp->vp_integer = c->hits;

		pairadd(&request->packet->vps, vp);
	}
}
예제 #2
0
/*
 *	Merge a cached entry into a REQUEST.
 */
static void cache_merge(rlm_cache_t *inst, REQUEST *request,
                        rlm_cache_entry_t *c)
{
    VALUE_PAIR *vp;

    rad_assert(request != NULL);
    rad_assert(c != NULL);

    vp = pairfind(request->config_items,
                  inst->cache_merge->attr,
                  inst->cache_merge->vendor,
                  TAG_ANY);
    if (vp && (vp->vp_integer == 0)) {
        RDEBUG2("Told not to merge entry into request");
        return;
    }

    if (c->control) {
        RDEBUG2("Merging cached control list:");
        rdebug_pair_list(2, request, c->control);

        vp = paircopy(c->control);
        pairmove(&request->config_items, &vp);
        pairfree(&vp);
    }

    if (c->request && request->packet) {
        RDEBUG2("Merging cached request list:");
        rdebug_pair_list(2, request, c->request);

        vp = paircopy(c->request);
        pairmove(&request->packet->vps, &vp);
        pairfree(&vp);
    }

    if (c->reply && request->reply) {
        RDEBUG2("Merging cached reply list:");
        rdebug_pair_list(2, request, c->reply);

        vp = paircopy(c->reply);
        pairmove(&request->reply->vps, &vp);
        pairfree(&vp);
    }

    if (inst->stats) {
        vp = pairalloc(inst->cache_entry_hits);
        rad_assert(vp != NULL);

        vp->vp_integer = c->hits;

        pairadd(&request->packet->vps, vp);
    }
}
예제 #3
0
/*
 *	Set the SQL user name.
 *
 *	We don't call the escape function here. The resulting string
 *	will be escaped later in the queries xlat so we don't need to
 *	escape it twice. (it will make things wrong if we have an
 *	escape candidate character in the username)
 */
int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username)
{
	char *expanded = NULL;
	VALUE_PAIR *vp = NULL;
	char const *sqluser;
	ssize_t len;

	if (username != NULL) {
		sqluser = username;
	} else if (inst->config->query_user[0] != '\0') {
		sqluser = inst->config->query_user;
	} else {
		return 0;
	}

	len = radius_axlat(&expanded, request, sqluser, NULL, NULL);
	if (len < 0) {
		return -1;
	}

	vp = pairalloc(request->packet, inst->sql_user);
	if (!vp) {
		talloc_free(expanded);
		return -1;
	}

	pairstrsteal(vp, expanded);
	RDEBUG2("SQL-User-Name set to '%s'", vp->vp_strvalue);
	vp->op = T_OP_SET;
	pairmove(request, &request->packet->vps, &vp);	/* needs to be pair move else op is not respected */

	return 0;
}
예제 #4
0
/*
 *	First, look for Exec-Program && Exec-Program-Wait.
 *
 *	Then, call exec_dispatch.
 */
static int exec_postauth(void *instance, REQUEST *request)
{
	int result;
	int exec_wait = 0;
	VALUE_PAIR *vp, *tmp;
	rlm_exec_t *inst = (rlm_exec_t *) instance;

	vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0);
	if (vp) {
		exec_wait = 0;

	} else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) {
		exec_wait = 1;
	}
	if (!vp) {
		if (!inst->program) return RLM_MODULE_NOOP;
		
		return exec_dispatch(instance, request);
	}

	tmp = NULL;
	result = radius_exec_program(vp->vp_strvalue, request, exec_wait,
				     NULL, 0, request->packet->vps, &tmp,
				     inst->shell_escape);

	/*
	 *	Always add the value-pairs to the reply.
	 */
	pairmove(&request->reply->vps, &tmp);
	pairfree(&tmp);

	if (result < 0) {
		/*
		 *	Error. radius_exec_program() returns -1 on
		 *	fork/exec errors.
		 */
		tmp = pairmake("Reply-Message", "Access denied (external check failed)", T_OP_SET);
		pairadd(&request->reply->vps, tmp);

		RDEBUG2("Login incorrect (external check failed)");

		request->reply->code = PW_AUTHENTICATION_REJECT;
		return RLM_MODULE_REJECT;
	}
	if (result > 0) {
		/*
		 *	Reject. radius_exec_program() returns >0
		 *	if the exec'ed program had a non-zero
		 *	exit status.
		 */
		request->reply->code = PW_AUTHENTICATION_REJECT;
		RDEBUG2("Login incorrect (external check said so)");
		return RLM_MODULE_REJECT;
	}

	return RLM_MODULE_OK;
}
예제 #5
0
/*
 *	First, look for Exec-Program && Exec-Program-Wait.
 *
 *	Then, call exec_dispatch.
 */
static rlm_rcode_t exec_postauth(void *instance, REQUEST *request)
{
	int result;
	int exec_wait = 0;
	VALUE_PAIR *vp, *tmp;
	rlm_exec_t *inst = (rlm_exec_t *) instance;

	vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
	if (vp) {
		exec_wait = 0;

	} else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != NULL) {
		exec_wait = 1;
	}
	if (!vp) {
		if (!inst->program) return RLM_MODULE_NOOP;
		
		return exec_dispatch(instance, request);
	}

	tmp = NULL;
	result = radius_exec_program(vp->vp_strvalue, request, exec_wait,
				     NULL, 0, request->packet->vps, &tmp,
				     inst->shell_escape);

	/*
	 *	Always add the value-pairs to the reply.
	 */
	pairmove(&request->reply->vps, &tmp);
	pairfree(&tmp);

	if (result < 0) {
		RDEBUG2("%s", module_failure_msg(request, "rlm_exec (%s): "
						 "Login incorrect (external "
						 "check failed)",
						 inst->xlat_name));

		request->reply->code = PW_AUTHENTICATION_REJECT;
		return RLM_MODULE_REJECT;
	}
	if (result > 0) {
		/*
		 *	Reject. radius_exec_program() returns >0
		 *	if the exec'ed program had a non-zero
		 *	exit status.
		 */
		request->reply->code = PW_AUTHENTICATION_REJECT;
		
		RDEBUG2("%s", module_failure_msg(request, "rlm_exec (%s): "
						 "Login incorrect (external "
						 "check said so)",
						 inst->xlat_name));
		return RLM_MODULE_REJECT;
	}

	return RLM_MODULE_OK;
}
예제 #6
0
/*
 *	First, look for Exec-Program && Exec-Program-Wait.
 *
 *	Then, call exec_dispatch.
 */
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
{
	rlm_exec_t	*inst = (rlm_exec_t *) instance;
	rlm_rcode_t 	rcode;
	int		status;

	char		out[1024];
	bool		we_wait = false;
	VALUE_PAIR	*vp, *tmp;

	vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
	if (vp) {
		we_wait = false;
	} else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != NULL) {
		we_wait = true;
	}
	if (!vp) {
		if (!inst->program) {
			return RLM_MODULE_NOOP;
		}

		rcode = exec_dispatch(instance, request);
		goto finish;
	}

	tmp = NULL;
	status = radius_exec_program(request, vp->vp_strvalue, we_wait, inst->shell_escape,
				     out, sizeof(out), inst->timeout,
				     request->packet->vps, &tmp);
	rcode = rlm_exec_status2rcode(request, out, strlen(out), status);

	/*
	 *	Always add the value-pairs to the reply.
	 */
	pairmove(request->reply, &request->reply->vps, &tmp);
	pairfree(&tmp);

	finish:
	switch (rcode) {
		case RLM_MODULE_FAIL:
		case RLM_MODULE_INVALID:
		case RLM_MODULE_REJECT:
			request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
			break;
		default:
			break;
	}

	return rcode;
}
예제 #7
0
/** Convert a valuepair string to VALUE_PAIR and insert it into a list
 *
 * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
 * and inserts it into the appropriate list.
 *
 * @param request Current request.
 * @param raw string to parse.
 * @param request_def to use if attribute isn't qualified.
 * @param list_def to use if attribute isn't qualified.
 * @return 0 on success, -1 on error.
 */
int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def)
{
	char const *p;
	size_t len;
	request_refs_t req;
	pair_lists_t list;

	VALUE_PAIR *vp = NULL;
	VALUE_PAIR **vps;

	p = raw;

	req = radius_request_name(&p, request_def);
	len = p - raw;
	if (req == REQUEST_UNKNOWN) {
		REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw);

		return -1;
	}
	raw += len;

	list = radius_list_name(&p, list_def);
	if (list == PAIR_LIST_UNKNOWN) {
		len = p - raw;

		REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw);

		return -1;
	}
	raw += len;

	if (radius_request(&request, req) < 0) {
		return -1;
	}

	vps = radius_list(request, list);
	if (!vps) {
		return -1;
	}

	if (userparse(request, raw, &vp) == T_OP_INVALID) {
		return -1;
	}

	pairmove(request, vps, &vp);

	return 0;
}
예제 #8
0
/*
 *	Allow single attribute values to be retrieved from the dhcp.
 */
static size_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request,
                                char const *fmt, char *out, size_t freespace)
{
    vp_cursor_t cursor;
    VALUE_PAIR *vp, *head = NULL;
    int decoded = 0;

    while (isspace((int) *fmt)) fmt++;


    if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
        *out = '\0';

        return 0;
    }

    if ((fr_dhcp_decode_options(request->packet,
                                vp->vp_octets, vp->length, &head) < 0) ||
            (!head)) {
        RWDEBUG("DHCP option decoding failed");
        goto fail;
    }


    for (vp = paircursor(&cursor, &head);
            vp;
            vp = pairnext(&cursor)) {
        decoded++;
    }

    pairmove(request->packet, &(request->packet->vps), &head);

    /* Free any unmoved pairs */
    pairfree(&head);

fail:

    snprintf(out, freespace, "%i", decoded);

    return strlen(out);
}
예제 #9
0
static int
remotedb_answer_builder(REQUEST *request, const char *password, const char *vlan)
{
        VALUE_PAIR *pair;

        radlog(L_DBG, "Building answer : password = %s, vlan = %s\n", password, vlan);

        pair = pairmake("NT-Password", password, T_OP_SET);	
        pairmove(&request->config_items, &pair);
        pairfree(&pair);

        pair = pairmake("Tunnel-Private-Group-Id", vlan, T_OP_SET);
        pairadd(&request->reply->vps, pair);
        
        pair = pairmake("Tunnel-Medium-Type", "6", T_OP_SET);
        pairadd(&request->reply->vps, pair);
        
        pair = pairmake("Tunnel-Type", "13", T_OP_SET);
        pairadd(&request->reply->vps, pair);
        
        return RLM_MODULE_OK;
}
예제 #10
0
/*
 *	Allow single attribute values to be retrieved from the dhcp.
 */
static size_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request,
			 	const char *fmt, char *out, size_t freespace)
{
	VALUE_PAIR *vp, *head = NULL, *next;
	int decoded = 0;
	
	while (isspace((int) *fmt)) fmt++;
	
	
	if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
		 *out = '\0';
		 
		 return 0;
	}
	
	if ((fr_dhcp_decode_options(vp->vp_octets, vp->length, &head) < 0) ||
	    (head == NULL)) {
		RDEBUG("WARNING: DHCP option decoding failed");
		goto fail;
	}
	
	next = head;
	
	do {
		 next = next->next;
		 decoded++;
	} while (next);
	
	pairmove(&(request->packet->vps), &head);
	
	/* Free any unmoved pairs */
	pairfree(&head);
	
	fail:
	
	snprintf(out, freespace, "%i", decoded);
			 
	return strlen(out);
}
예제 #11
0
static int mongo_authorize(void *instance, REQUEST *request)
{
  if (request->username == NULL)
  	return RLM_MODULE_NOOP;
  	
  rlm_mongo_t *data = (rlm_mongo_t *) instance;
	
	char password[MONGO_STRING_LENGTH] = "";
	char mac[MONGO_STRING_LENGTH] = "";
	
	if (strcmp(data->mac_field, "") != 0) {
		char mac_temp[MONGO_STRING_LENGTH] = "";
		radius_xlat(mac_temp, MONGO_STRING_LENGTH, "%{Calling-Station-Id}", request, NULL);
		format_mac(mac_temp, mac);
  } 
	
	if (!find_radius_options(data, request->username->vp_strvalue, mac, password)) {
		return RLM_MODULE_REJECT; 
	}
	
	RDEBUG("Authorisation request by username -> \"%s\"\n", request->username->vp_strvalue);
	RDEBUG("Password found in MongoDB -> \"%s\"\n\n", password);
	
	VALUE_PAIR *vp;

	/* quiet the compiler */
	instance = instance;
	request = request;

 	vp = pairmake("Cleartext-Password", password, T_OP_SET);
 	if (!vp) return RLM_MODULE_FAIL;
 	
	pairmove(&request->config_items, &vp);
	pairfree(&vp);

	return RLM_MODULE_OK;
}
예제 #12
0
/*
 *  Dispatch an exec method
 */
static int exec_dispatch(void *instance, REQUEST *request)
{
	int result;
	VALUE_PAIR **input_pairs, **output_pairs;
	VALUE_PAIR *answer = NULL;
	rlm_exec_t *inst = (rlm_exec_t *) instance;

	/*
	 *	We need a program to execute.
	 */
	if (!inst->program) {
		radlog(L_ERR, "rlm_exec (%s): We require a program to execute",
		       inst->xlat_name);
		return RLM_MODULE_FAIL;
	}

	/*
	 *	See if we're supposed to execute it now.
	 */
	if (!((inst->packet_code == 0) ||
	      (request->packet->code == inst->packet_code) ||
	      (request->reply->code == inst->packet_code)
#ifdef WITH_PROXY
	      || (request->proxy &&
	       (request->proxy->code == inst->packet_code)) ||
	      (request->proxy_reply &&
	       (request->proxy_reply->code == inst->packet_code))
#endif
		    )) {
		RDEBUG2("Packet type is not %s.  Not executing.",
		       inst->packet_type);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Decide what input/output the program takes.
	 */
	input_pairs = decode_string(request, inst->input);
	output_pairs = decode_string(request, inst->output);

	if (!input_pairs) {
		RDEBUG2("WARNING: Possible parse error in %s",
			inst->input);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	It points to the attribute list, but the attribute
	 *	list is empty.
	 */
	if (!*input_pairs) {
		RDEBUG2("WARNING! Input pairs are empty.  No attributes will be passed to the script");
	}

	/*
	 *	This function does it's own xlat of the input program
	 *	to execute.
	 *
	 *	FIXME: if inst->program starts with %{, then
	 *	do an xlat ourselves.  This will allow us to do
	 *	program = %{Exec-Program}, which this module
	 *	xlat's into it's string value, and then the
	 *	exec program function xlat's it's string value
	 *	into something else.
	 */
	result = radius_exec_program(inst->program, request,
				     inst->wait, NULL, 0,
				     *input_pairs, &answer, inst->shell_escape);
	if (result < 0) {
		radlog(L_ERR, "rlm_exec (%s): External script failed",
		       inst->xlat_name);
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Move the answer over to the output pairs.
	 *
	 *	If we're not waiting, then there are no output pairs.
	 */
	if (output_pairs) pairmove(output_pairs, &answer);

	pairfree(&answer);

	if (result == 0) {
		return RLM_MODULE_OK;
	}
	if (result > RLM_MODULE_NUMCODES) {
		return RLM_MODULE_FAIL;
	}
	return result-1;
}
예제 #13
0
/*
 *  Dispatch an exec method
 */
static rlm_rcode_t exec_dispatch(void *instance, REQUEST *request)
{
	rlm_exec_t	*inst = (rlm_exec_t *)instance;
	rlm_rcode_t	rcode;
	int		status;

	VALUE_PAIR	**input_pairs = NULL, **output_pairs = NULL;
	VALUE_PAIR	*answer = NULL;
	char		out[1024];

	/*
	 *	We need a program to execute.
	 */
	if (!inst->program) {
		ERROR("rlm_exec (%s): We require a program to execute", inst->xlat_name);
		return RLM_MODULE_FAIL;
	}

	/*
	 *	See if we're supposed to execute it now.
	 */
	if (!((inst->packet_code == 0) || (request->packet->code == inst->packet_code) ||
	      (request->reply->code == inst->packet_code)
#ifdef WITH_PROXY
	      || (request->proxy && (request->proxy->code == inst->packet_code)) ||
	      (request->proxy_reply && (request->proxy_reply->code == inst->packet_code))
#endif
		    )) {
		RDEBUG2("Packet type is not %s. Not executing.", inst->packet_type);

		return RLM_MODULE_NOOP;
	}

	/*
	 *	Decide what input/output the program takes.
	 */
	if (inst->input) {
		input_pairs = radius_list(request, inst->input_list);
		if (!input_pairs) {
			return RLM_MODULE_INVALID;
		}
	}

	if (inst->output) {
		output_pairs = radius_list(request, inst->output_list);
		if (!output_pairs) {
			return RLM_MODULE_INVALID;
		}
	}

	/*
	 *	This function does it's own xlat of the input program
	 *	to execute.
	 */
	status = radius_exec_program(request, inst->program, inst->wait, inst->shell_escape,
				     out, sizeof(out), inst->timeout,
				     inst->input ? *input_pairs : NULL,
				     inst->output ? &answer : NULL);
	rcode = rlm_exec_status2rcode(request, out, strlen(out), status);

	/*
	 *	Move the answer over to the output pairs.
	 *
	 *	If we're not waiting, then there are no output pairs.
	 */
	if (inst->output) {
		pairmove(request, output_pairs, &answer);
	}
	pairfree(&answer);

	return rcode;
}
예제 #14
0
/*
 * 	Call the function_name inside the module
 * 	Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
 *
 */
static int rlmperl_call(void *instance, REQUEST *request, char *function_name)
{

	PERL_INST	*inst = instance;
	VALUE_PAIR	*vp;
	int		exitstatus=0, count;
	STRLEN		n_a;

	HV		*rad_reply_hv;
	HV		*rad_check_hv;
	HV		*rad_request_hv;
	HV		*rad_request_proxy_hv;
	HV		*rad_request_proxy_reply_hv;

#ifdef USE_ITHREADS
	POOL_HANDLE	*handle;

	if ((handle = pool_pop(instance)) == NULL) {
		return RLM_MODULE_FAIL;
	}

	radlog(L_DBG,"found interpetator at address 0x%lx",(unsigned long) handle->clone);
	{
	dTHXa(handle->clone);
	PERL_SET_CONTEXT(handle->clone);
	}
#else
	PERL_SET_CONTEXT(inst->perl);
	radlog(L_DBG,"Using perl at 0x%lx",(unsigned long) inst->perl);
#endif
	{
	dSP;

	ENTER;
	SAVETMPS;


	/*
	 *	Radius has told us to call this function, but none
	 *	is defined.
	 */
	if (!function_name) {
		return RLM_MODULE_FAIL;
	}

	rad_reply_hv = get_hv("RAD_REPLY",1);
	rad_check_hv = get_hv("RAD_CHECK",1);
	rad_request_hv = get_hv("RAD_REQUEST",1);
	rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
	rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);


	perl_store_vps(request->reply->vps, rad_reply_hv);
	perl_store_vps(request->config_items, rad_check_hv);
	perl_store_vps(request->packet->vps, rad_request_hv);
	
	if (request->proxy != NULL) {
		perl_store_vps(request->proxy->vps, rad_request_proxy_hv);
	} else {
		hv_undef(rad_request_proxy_hv);
	}

	if (request->proxy_reply !=NULL) {
		perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv);
	} else {
		hv_undef(rad_request_proxy_reply_hv);
	}	
	
	vp = NULL;


	PUSHMARK(SP);
	/*
	* This way %RAD_xx can be pushed onto stack as sub parameters.
	* XPUSHs( newRV_noinc((SV *)rad_request_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_check_hv) );
	* PUTBACK;
	*/

	count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);

	SPAGAIN;

	if (SvTRUE(ERRSV)) {
		radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n",
		       inst->module,
		       function_name, SvPV(ERRSV,n_a));
		POPs;
	}

	if (count == 1) {
		exitstatus = POPi;
		if (exitstatus >= 100 || exitstatus < 0) {
			exitstatus = RLM_MODULE_FAIL;
		}
	}
	

	PUTBACK;
	FREETMPS;
	LEAVE;


	if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) {
		pairmove(&request->reply->vps, &vp);
		pairfree(&vp);
	}

	if ((get_hv_content(rad_check_hv, &vp)) > 0 ) {
		pairmove(&request->config_items, &vp);
		pairfree(&vp);
	}
	
	if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) {
		pairfree(&request->proxy_reply->vps);
		pairmove(&request->proxy_reply->vps, &vp);
		pairfree(&vp);
	}
	}
#ifdef USE_ITHREADS
	pool_release(handle,instance);
	radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone);
#endif

	return exitstatus;
}
예제 #15
0
/*
 *	Evaluate a 'packet .= {attrs}' statement
 */
static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
{
	const policy_attributes_t *this;
	VALUE_PAIR **vps = NULL;
	VALUE_PAIR *vp, *head, **tail;
	const policy_item_t *attr;
	policy_lex_t this_how;

	this = (const policy_attributes_t *) item;

	switch (this->where) {
	case POLICY_RESERVED_CONTROL:
		vps = &(state->request->config_items);
		break;

	case POLICY_RESERVED_REQUEST:
		vps = &(state->request->packet->vps);
		break;

	case POLICY_RESERVED_REPLY:
		vps = &(state->request->reply->vps);
		break;

#ifdef WITH_PROXY
	case POLICY_RESERVED_PROXY_REQUEST:
		if (!state->request->proxy) return 0; /* FIXME: print error */
		vps = &(state->request->proxy->vps);
		break;

	case POLICY_RESERVED_PROXY_REPLY:
		if (!state->request->proxy_reply) return 0; /* FIXME: print error */
		vps = &(state->request->proxy_reply->vps);
		break;
#endif

	default:
		return 0;
	}

	head = NULL;
	tail = &head;

	for (attr = this->attributes; attr != NULL; attr = attr->next) {
		if (attr->type != POLICY_TYPE_ASSIGNMENT) {
			fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
			pairfree(&head);
			return 0;
		}

		vp = assign2vp(state->request, (const policy_assignment_t *) attr);
		if (!vp) {
			fprintf(stderr, "Failed to allocate VP\n");
			pairfree(&head);
			return 0;
		}
		*tail = vp;
		tail = &(vp->next);
	}

	this_how = this->how;
 retry_how:
	switch (this_how) {
	case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */
		pairfree(vps);
		*vps = head;
		break;

	case POLICY_LEX_AFTER_TAIL_ASSIGN:
		pairmove(vps, &head);
		pairfree(&head);
		break;

	case POLICY_LEX_ASSIGN: /* 'union' */
		pairmove(vps, &head);
		pairfree(&head);
		break;

	case POLICY_LEX_BEFORE_HEAD_ASSIGN:
		pairmove(&head, vps);
		pairfree(vps);
		*vps = head;
		break;

	case POLICY_LEX_AFTER_TAIL_EQUALS:
	case POLICY_LEX_CONCAT_EQUALS:
		pairadd(vps, head);
		break;

	case POLICY_LEX_BEFORE_HEAD_EQUALS:
		pairadd(&head, *vps);
		*vps = head;
		break;

	case POLICY_LEX_BEFORE_WHERE_EQUALS:
	case POLICY_LEX_AFTER_WHERE_EQUALS:
	case POLICY_LEX_BEFORE_WHERE_ASSIGN:
	case POLICY_LEX_AFTER_WHERE_ASSIGN:
		/* find location*/
		{
			VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp;

			for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) {
				vpnext = lvp->next;
				lvp->next = NULL;
				if (evaluate_condition(state, this->where_loc))
					break;
				lvp->next = vpnext;
			}

			if (lvp) { 
				switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					if (vpprev) {
						lvp->next = vpnext;
						vpnext = lvp;
						vpprev->next = NULL;
						lvp = vpprev;
					}
				default: /* always reached */
					break;
				}

				switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
					if (vpprev) 
						pairadd(&lvp, head);
					else
						*vps = lvp = head;
					break;
 				case POLICY_LEX_AFTER_WHERE_EQUALS:
 					pairadd(&lvp, head);
					break;
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					if (vpprev) {
						pairmove(&lvp, &head);
						pairfree(&head);
					}
					else
						*vps = lvp = head;
					break;
				case POLICY_LEX_AFTER_WHERE_ASSIGN:
					pairmove(&lvp, &head);
					pairfree(&head);
					break;
				default:/*never reached*/
					break;
				}	
				for( ; lvp && lvp->next; lvp = lvp->next);
				if (lvp)
					lvp->next = vpnext;
				break;
			}

			switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
					this_how = POLICY_LEX_BEFORE_HEAD_EQUALS;
					break;
				case POLICY_LEX_AFTER_WHERE_EQUALS:
					this_how = POLICY_LEX_AFTER_TAIL_EQUALS;
					break;
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN;
					break;
				case POLICY_LEX_AFTER_WHERE_ASSIGN:
					this_how = POLICY_LEX_AFTER_TAIL_ASSIGN;
					break;
				default: /*never reached*/
					break;
			}
			goto retry_how; 
		}
		/* FALL-THROUGH */

	default:
		fprintf(stderr, "HUH?\n");
		pairfree(&head);
		return 0;
	}

	state->rcode = RLM_MODULE_UPDATED; /* we did stuff */

	return 1;
}
예제 #16
0
/*
 *	Common code called by everything below.
 */
static rlm_rcode_t file_common(rlm_files_t *inst, REQUEST *request,
		       char const *filename, fr_hash_table_t *ht,
		       VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs)
{
	char const	*name, *match;
	VALUE_PAIR	*check_tmp;
	VALUE_PAIR	*reply_tmp;
	const PAIR_LIST	*user_pl, *default_pl;
	int		found = 0;
	PAIR_LIST	my_pl;
	char		buffer[256];

	if (!inst->key) {
		VALUE_PAIR	*namepair;

		namepair = request->username;
		name = namepair ? namepair->vp_strvalue : "NONE";
	} else {
		int len;

		len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL);
		if (len < 0) {
			return RLM_MODULE_FAIL;
		}
		
		name = len ? buffer : "NONE";
	}

	if (!ht) return RLM_MODULE_NOOP;

	my_pl.name = name;
	user_pl = fr_hash_table_finddata(ht, &my_pl);
	my_pl.name = "DEFAULT";
	default_pl = fr_hash_table_finddata(ht, &my_pl);

	/*
	 *	Find the entry for the user.
	 */
	while (user_pl || default_pl) {
		const PAIR_LIST *pl;

		if (!default_pl && user_pl) {
			pl = user_pl;
			match = name;
			user_pl = user_pl->next;

		} else if (!user_pl && default_pl) {
			pl = default_pl;
			match = "DEFAULT";
			default_pl = default_pl->next;

		} else if (user_pl->order < default_pl->order) {
			pl = user_pl;
			match = name;
			user_pl = user_pl->next;

		} else {
			pl = default_pl;
			match = "DEFAULT";
			default_pl = default_pl->next;
		}

		if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) {
			RDEBUG2("%s: Matched entry %s at line %d",
			       filename, match, pl->lineno);
			found = 1;
			check_tmp = paircopy(request, pl->check);

			/* ctx may be reply or proxy */
			reply_tmp = paircopy(request, pl->reply);
			radius_xlat_move(request, reply_pairs, &reply_tmp);
			pairmove(request, &request->config_items, &check_tmp);
			pairfree(&reply_tmp);
			pairfree(&check_tmp);

			/*
			 *	Fallthrough?
			 */
			if (!fallthrough(pl->reply))
				break;
		}
	}

	/*
	 *	Remove server internal parameters.
	 */
	pairdelete(reply_pairs, PW_FALL_THROUGH, 0, TAG_ANY);

	/*
	 *	See if we succeeded.
	 */
	if (!found)
		return RLM_MODULE_NOOP; /* on to the next module */

	return RLM_MODULE_OK;

}
예제 #17
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;
}