Ejemplo n.º 1
0
/*************************************************************************
 *
 *	Function: sql_getvpdata
 *
 *	Purpose: Get any group check or reply pairs
 *
 *************************************************************************/
int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle,
		  VALUE_PAIR **pair, char const *query)
{
	rlm_sql_row_t	row;
	int		rows = 0;
	sql_rcode_t	rcode;

	rad_assert(request);

	rcode = rlm_sql_select_query(inst, request, handle, query);
	if (rcode != RLM_SQL_OK) return -1; /* error handled by rlm_sql_select_query */

	while (rlm_sql_fetch_row(&row, inst, request, handle) == 0) {
		if (!row) break;
		if (sql_userparse(ctx, request, pair, row) != 0) {
			REDEBUG("Error parsing user data from database result");

			(inst->module->sql_finish_select_query)(*handle, inst->config);

			return -1;
		}
		rows++;
	}
	(inst->module->sql_finish_select_query)(*handle, inst->config);

	return rows;
}
Ejemplo n.º 2
0
/*
 *	This is a wraper for radius_axlat
 *	Now users are able to get data that is accessible only via xlat
 *	e.g. %{client:...}
 *	Call syntax is radiusd::xlat(string), string will be handled the
 *	same way it is described in EXPANSIONS section of man unlang
 */
static XS(XS_radiusd_xlat)
{
	dXSARGS;
	char *in_str;
	char *expanded;
	ssize_t slen;
	SV *rad_requestp_sv;
	REQUEST *request;

	if (items != 1) croak("Usage: radiusd::xlat(string)");

	rad_requestp_sv = get_sv("RAD___REQUESTP", 0);
	if (rad_requestp_sv == NULL) croak("Can not evalue xlat, RAD___REQUESTP is not set!");

	request = INT2PTR(REQUEST *, SvIV(rad_requestp_sv));

	in_str = (char *) SvPV(ST(0), PL_na);
	expanded = NULL;
	slen = radius_axlat(&expanded, request, in_str, NULL, NULL);

	if (slen < 0) {
		REDEBUG("Error parsing xlat '%s'", in_str);
		XSRETURN_UNDEF;
	}


	XST_mPV(0, expanded);
	talloc_free(expanded);
	XSRETURN(1);
}
Ejemplo n.º 3
0
/** Print a list of valuepairs to the request list.
 *
 * @param[in] level Debug level (1-4).
 * @param[in] request to read logging params from.
 * @param[in] vp to print.
 */
void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp)
{
	vp_cursor_t cursor;
	char buffer[256];
	if (!vp || !request || !request->log.func) return;

	if (!radlog_debug_enabled(L_DBG, level, request)) return;

	for (vp = fr_cursor_init(&cursor, &vp);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
		/*
		 *	Take this opportunity to verify all the VALUE_PAIRs are still valid.
		 */
		if (!talloc_get_type(vp, VALUE_PAIR)) {
			REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));

			fr_log_talloc_report(vp);
			rad_assert(0);
		}

		vp_prints(buffer, sizeof(buffer), vp);
		RDEBUGX(level, "\t%s", buffer);
	}
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/*
 * Query the database executing a command with no result rows
 */
static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sqlippool_t *data, REQUEST * request,
                             char * param, int param_len)
{
    char query[MAX_QUERY_LEN];
    char *expanded = NULL;

    int ret;

    /*
     *	If we don't have a command, do nothing.
     */
    if (!*fmt) return 0;

    /*
     *	@todo this needs to die (should just be done in xlat expansion)
     */
    sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);

    if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
        return 0;
    }

    ret = data->sql_inst->sql_query(&handle, data->sql_inst, expanded);
    if (!ret) {
        REDEBUG("database query error in: '%s'", expanded);
        talloc_free(expanded);

        return 0;
    }
    talloc_free(expanded);

    (data->sql_inst->module->sql_finish_query)(handle, data->sql_inst->config);
    return 0;
}
Ejemplo n.º 6
0
/**
 * @brief Convert base64 to hex
 *
 * Example: "%{base64tohex:Zm9v}" == "666f6f"
 */
static size_t base64_to_hex_xlat(UNUSED void *instance, UNUSED REQUEST *request,
				 char const *fmt, char *out, size_t outlen)
{	
	uint8_t decbuf[1024], *p;
	
	ssize_t declen;
	size_t freespace = outlen;
	ssize_t len = strlen(fmt);

	*out = '\0';
		
	declen = fr_base64_decode(fmt, len, decbuf, sizeof(decbuf));
	if (declen < 0) {
		REDEBUG("Base64 string invalid");
		return 0;
	}
	
	p = decbuf;
	while ((declen-- > 0) && (--freespace > 0)) {
		if (freespace < 3) {
			break;
		}

		snprintf(out, 3, "%02x", *p++);
		
		/* Already decremented */
		freespace -= 1;
		out += 2;
	}

	return outlen - freespace;
}
Ejemplo n.º 7
0
/** Resolve request to a request.
 *
 * Resolve name to a current request.
 *
 * @see radius_list
 * @param[in,out] context Base context to use, and to write the result back to.
 * @param[in] name (request) to resolve to.
 * @return 0 if request is valid in this context, else -1.
 */
int radius_request(REQUEST **context, request_refs_t name)
{
	REQUEST *request = *context;
	
	switch (name) {
		case REQUEST_CURRENT:
			return 0;
		
		case REQUEST_PARENT:	/* for future use in request chaining */
		case REQUEST_OUTER:
			if (!request->parent) {
				REDEBUG("Specified request \"%s\" is not available in this context",
				        fr_int2str(request_refs, name, "<INVALID>"));
				return -1;
			}
			
			*context = request->parent;
			
			break;
	
		case REQUEST_UNKNOWN:
		default:
			rad_assert(0);
			return -1;
	}
	
	return 0;
}
Ejemplo n.º 8
0
/*
 * The xlat function
 */
static ssize_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
{

	rlm_perl_t	*inst = (rlm_perl_t *) instance;
	char		*tmp;
	char const	*p, *q;
	int		count;
	size_t		ret = 0;
	STRLEN		n_a;

#ifdef USE_ITHREADS
	PerlInterpreter *interp;

	pthread_mutex_lock(&inst->clone_mutex);
	interp = rlm_perl_clone(inst->perl, inst->thread_key);
	{
		dTHXa(interp);
		PERL_SET_CONTEXT(interp);
	}
	pthread_mutex_unlock(&inst->clone_mutex);
#else
	PERL_SET_CONTEXT(inst->perl);
#endif
	{
		dSP;
		ENTER;SAVETMPS;

		PUSHMARK(SP);

		p = fmt;
		while ((q = strchr(p, ' '))) {
			XPUSHs(sv_2mortal(newSVpvn(p, p - q)));

			p = q + 1;
		}

		PUTBACK;

		count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);

		SPAGAIN;
		if (SvTRUE(ERRSV)) {
			REDEBUG("Exit %s", SvPV(ERRSV,n_a));
			(void)POPs;
		} else if (count > 0) {
			tmp = POPp;
			strlcpy(out, tmp, freespace);
			ret = strlen(out);

			RDEBUG("Len is %zu , out is %s freespace is %zu", ret, out, freespace);
		}

		PUTBACK ;
		FREETMPS ;
		LEAVE ;

	}

	return ret;
}
Ejemplo n.º 9
0
static int sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp, VALUE_PAIR *check,
			UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
{
	rlm_sql_handle_t *handle;
	rlm_sql_t *inst = instance;
	rlm_sql_grouplist_t *head, *entry;

	RDEBUG("sql_groupcmp");
	if (!check || !check->length){
		RDEBUG("sql_groupcmp: Illegal group name");
		return 1;
	}
	if (!request){
		RDEBUG("sql_groupcmp: NULL request");
		return 1;
	}
	/*
	 *	Set, escape, and check the user attr here
	 */
	if (sql_set_user(inst, request, NULL) < 0)
		return 1;

	/*
	 *	Get a socket for this lookup
	 */
	handle = sql_get_socket(inst);
	if (!handle) {
		return 1;
	}

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (sql_get_grouplist(inst, handle, request, &head) < 0) {
		REDEBUG("Error getting group membership");
		sql_release_socket(inst, handle);
		return 1;
	}

	for (entry = head; entry != NULL; entry = entry->next) {
		if (strcmp(entry->name, check->vp_strvalue) == 0){
			RDEBUG("sql_groupcmp finished: User is a member of group %s",
			       check->vp_strvalue);
			talloc_free(head);
			sql_release_socket(inst, handle);
			return 0;
		}
	}

	/* Free the grouplist */
	talloc_free(head);
	sql_release_socket(inst,handle);

	RDEBUG("sql_groupcmp finished: User is NOT a member of group %s",
	       check->vp_strvalue);

	return 1;
}
Ejemplo n.º 10
0
/** Call the driver's sql_select_query method, reconnecting if necessary.
 *
 * @note Caller must call ``(inst->module->sql_finish_select_query)(handle, inst->config);``
 *	after they're done with the result.
 *
 * @param inst #rlm_sql_t instance data.
 * @param request Current request.
 * @param handle to query the database with. *handle should not be NULL, as this indicates
 *	  previous reconnection attempt has failed.
 * @param query to execute. Should not be zero length.
 * @return
 *	- #RLM_SQL_OK on success.
 *	- #RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL).
 *	- #RLM_SQL_QUERY_INVALID, #RLM_SQL_ERROR on invalid query or connection error.
 */
sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle,  char const *query)
{
	int ret = RLM_SQL_ERROR;
	int i, count;

	/* Caller should check they have a valid handle */
	rad_assert(*handle);

	/* There's no query to run, return an error */
	if (query[0] == '\0') {
		if (request) REDEBUG("Zero length query");

		return RLM_SQL_QUERY_INVALID;
	}

	/*
	 *  inst->pool may be NULL is this function is called by mod_conn_create.
	 */
	count = inst->pool ? fr_connection_get_num(inst->pool) : 0;

	/*
	 *  For sanity, for when no connections are viable, and we can't make a new one
	 */
	for (i = 0; i < (count + 1); i++) {
		ROPTIONAL(RDEBUG2, DEBUG2, "Executing select query: %s", query);

		ret = (inst->module->sql_select_query)(*handle, inst->config, query);
		switch (ret) {
		case RLM_SQL_OK:
			break;

		/*
		 *	Run through all available sockets until we exhaust all existing
		 *	sockets in the pool and fail to establish a *new* connection.
		 */
		case RLM_SQL_RECONNECT:
			*handle = fr_connection_reconnect(inst->pool, *handle);
			/* Reconnection failed */
			if (!*handle) return RLM_SQL_RECONNECT;
			/* Reconnection succeeded, try again with the new handle */
			continue;

		case RLM_SQL_QUERY_INVALID:
		case RLM_SQL_ERROR:
		default:
			rlm_sql_print_error(inst, request, *handle, false);
			(inst->module->sql_finish_select_query)(*handle, inst->config);
			break;
		}

		return ret;
	}

	ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");

	return RLM_SQL_ERROR;
}
Ejemplo n.º 11
0
/*
 * Query the database expecting a single result row
 */
static int sqlippool_query1(char *out, int outlen, char const *fmt,
                            rlm_sql_handle_t *handle, rlm_sqlippool_t *data,
                            REQUEST *request, char *param, int param_len)
{
    char query[MAX_QUERY_LEN];
    char *expanded = NULL;

    int rlen, retval;

    /*
     *	@todo this needs to die (should just be done in xlat expansion)
     */
    sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);

    rad_assert(request != NULL);

    *out = '\0';

    /*
     *	Do an xlat on the provided string
     */
    if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
        return 0;
    }
    retval = data->sql_inst->sql_select_query(&handle, data->sql_inst, expanded);
    talloc_free(expanded);

    if (retval != 0) {
        REDEBUG("database query error on '%s'", query);

        return 0;
    }

    if (!data->sql_inst->sql_fetch_row(&handle, data->sql_inst)) {
        if (handle->row) {
            if (handle->row[0]) {
                if ((rlen = strlen(handle->row[0])) < outlen) {
                    strcpy(out, handle->row[0]);
                    retval = rlen;
                } else {
                    RDEBUG("insufficient string space");
                }
            } else {
                RDEBUG("row[0] returned NULL");
            }
        } else {
            RDEBUG("SQL query did not return any results");
        }
    } else {
        RDEBUG("SQL query did not succeed");
    }

    (data->sql_inst->module->sql_finish_select_query)(handle, data->sql_inst->config);

    return retval;
}
Ejemplo n.º 12
0
/** Perform a search and map the result of the search to server attributes
 *
 * @param[in] mod_inst	#rlm_csv_t.
 * @param[in] proc_inst	mapping map entries to field numbers.
 * @param[in,out]	request The current request.
 * @param[in] key	key to look for
 * @param[in] maps	Head of the map list.
 * @return
 *	- #RLM_MODULE_NOOP no rows were returned.
 *	- #RLM_MODULE_UPDATED if one or more #VALUE_PAIR were added to the #REQUEST.
 *	- #RLM_MODULE_FAIL if an error occurred.
 */
static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, REQUEST *request,
				fr_value_box_t **key, vp_map_t const *maps)
{
	rlm_rcode_t		rcode = RLM_MODULE_UPDATED;
	rlm_csv_t		*inst = talloc_get_type_abort(mod_inst, rlm_csv_t);
	rlm_csv_entry_t		*e;
	vp_map_t const		*map;

	if (!*key) {
		REDEBUG("CSV key cannot be (null)");
		return RLM_MODULE_FAIL;
	}

	if (fr_value_box_list_concat(request, *key, key, FR_TYPE_STRING, true) < 0) {
		REDEBUG("Failed concatenating key elements");
		return RLM_MODULE_FAIL;
	}

	e = rbtree_finddata(inst->tree, &(rlm_csv_entry_t){ .key = (*key)->vb_strvalue });
Ejemplo n.º 13
0
static ssize_t date_encode_strftime(char **out, size_t outlen, rlm_date_t const *inst,
				    REQUEST *request, time_t date)
{
	struct tm tminfo;

	if (inst->utc) {
		if (gmtime_r(&date, &tminfo) == NULL) {
			REDEBUG("Failed converting time string to gmtime: %s", fr_syserror(errno));
			return -1;
		}
	} else {
		if (localtime_r(&date, &tminfo) == NULL) {
			REDEBUG("Failed converting time string to localtime: %s", fr_syserror(errno));
			return -1;
		}
	}

	return strftime(*out, outlen, inst->fmt, &tminfo);
}
Ejemplo n.º 14
0
/*
 *	See if the counter matches.
 */
static int sqlcounter_cmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *req , VALUE_PAIR *check,
			  UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
{
	rlm_sqlcounter_t *inst = instance;
	uint64_t counter;

	char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN];
	char *expanded = NULL;
	size_t len;

	/* First, expand %k, %b and %e in query */
	if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) {
		REDEBUG("Insufficient query buffer space");

		return RLM_MODULE_FAIL;
	}

	/* Then combine that with the name of the module were using to do the query */
	len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst);
	if (len >= sizeof(query) - 1) {
		REDEBUG("Insufficient query buffer space");

		return RLM_MODULE_FAIL;
	}

	/* Finally, xlat resulting SQL query */
	if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	if (sscanf(expanded, "%" PRIu64, &counter) != 1) {
		RDEBUG2("No integer found in string \"%s\"", expanded);
	}
	talloc_free(expanded);

	if (counter < check->vp_integer64) {
		return -1;
	}
	if (counter > check->vp_integer64) {
		return 1;
	}
	return 0;
}
Ejemplo n.º 15
0
static ssize_t date_convert_string(REQUEST *request, char **out, size_t outlen,
				   const char *str, const char *fmt)
{
	struct tm tminfo;
	time_t date = 0;

	if (strptime(str, fmt, &tminfo) == NULL) {
		REDEBUG("Failed to parse time string \"%s\" as format '%s'", str, fmt);
		return -1;
	}

	date = mktime(&tminfo);
	if (date < 0) {
		REDEBUG("Failed converting parsed time into unix time");
		return -1;
	}

	return snprintf(*out, outlen, "%" PRIu64, (uint64_t) date);
}
Ejemplo n.º 16
0
static ssize_t xlat_idna(void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t freespace)
{
	rlm_idn_t *inst = instance;
	char *idna = NULL;
	int res;
	size_t len;
        int flags = 0;

        if (inst->use_std3_ascii_rules) {
        	flags |= IDNA_USE_STD3_ASCII_RULES;
        }
        if (inst->allow_unassigned) {
        	flags |= IDNA_ALLOW_UNASSIGNED;
	}
	
        res = idna_to_ascii_8z(fmt, &idna, flags);
	if (res) {
		if (idna) { 
			free (idna); /* Docs unclear, be safe. */
		}

		REDEBUG("%s", idna_strerror(res));
		return -1;
	}

        len = strlen(idna);

	/* 253 is max DNS length */
        if (!((len < (freespace - 1)) && (len <= 253))) {
	        /* Never provide a truncated result, as it may be queried. */
		REDEBUG("Conversion was truncated");
		
		free(idna);
		return -1;

	}

	strlcpy(out, idna, freespace);
	free(idna);
	
	return len;
}
Ejemplo n.º 17
0
USES_APPLE_DEPRECATED_API	/* OpenSSL API has been deprecated by Apple */

#include <freeradius-devel/radiusd.h>

#ifdef WITH_TLS
void cbtls_info(SSL const *s, int where, int ret)
{
	char const *str, *state;
	int w;
	REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
	char buffer[1024];

	w = where & ~SSL_ST_MASK;
	if (w & SSL_ST_CONNECT) str="    TLS_connect";
	else if (w & SSL_ST_ACCEPT) str="    TLS_accept";
	else str="    (other)";

	state = SSL_state_string_long(s);
	state = state ? state : "NULL";
	buffer[0] = '\0';

	if (where & SSL_CB_LOOP) {
		RDEBUG2("%s: %s", str, state);
	} else if (where & SSL_CB_HANDSHAKE_START) {
		RDEBUG2("%s: %s", str, state);
	} else if (where & SSL_CB_HANDSHAKE_DONE) {
		RDEBUG2("%s: %s", str, state);
	} else if (where & SSL_CB_ALERT) {
		str=(where & SSL_CB_READ)?"read":"write";

		snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s",
			 str,
			 SSL_alert_type_string_long(ret),
			 SSL_alert_desc_string_long(ret));
	} else if (where & SSL_CB_EXIT) {
		if (ret == 0) {
			snprintf(buffer, sizeof(buffer), "%s: failed in %s",
				 str, state);

		} else if (ret < 0) {
			if (SSL_want_read(s)) {
				RDEBUG2("%s: Need to read more data: %s",
				       str, state);
			} else {
				snprintf(buffer, sizeof(buffer),
					 "%s: error in %s", str, state);
			}
		}
	}

	if (buffer[0] && request) {
		REDEBUG("SSL says: %s", buffer);
	}
}
Ejemplo n.º 18
0
/** Generate the HMAC-SHA1 of a string or attribute
 *
 * Example: "%{hmacsha1:foo bar}" == "Zm9v"
 */
static ssize_t hmac_sha1_xlat(UNUSED void *instance, UNUSED REQUEST *request,
			      char const *fmt, char *out, size_t outlen)
{
	uint8_t const *data, *key;
	char const *p;
	ssize_t data_len, key_len;
	uint8_t digest[SHA1_DIGEST_LENGTH];
	char data_ref[256];

	if (outlen <= (sizeof(digest) * 2)) {
		REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes",
			(sizeof(digest) * 2) + 1, outlen);
		return -1;
	}

	p = strchr(fmt, ' ');
	if (!p) {
		REDEBUG("HMAC requires exactly two arguments (&data &key)");
		return -1;
	}

	if ((size_t)(p - fmt) >= sizeof(data_ref)) {
		REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes",
		        (p - fmt) + 1, sizeof(data_ref));

		return -1;
	}
	strlcpy(data_ref, fmt, (p - fmt) + 1);

	data_len = xlat_fmt_to_ref(&data, request, data_ref);
	if (data_len < 0) return -1;

	while (isspace(*p) && p++);

	key_len = xlat_fmt_to_ref(&key, request, p);
	if (key_len < 0) return -1;

	fr_hmac_sha1(digest, data, data_len, key, key_len);

	return fr_bin2hex(out, digest, sizeof(digest));
}
Ejemplo n.º 19
0
/*
 *	Do xlat of strings.
 */
static ssize_t exec_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
{
	int		result;
	rlm_exec_t	*inst = instance;
	VALUE_PAIR	**input_pairs = NULL;
	char *p;

	if (!inst->wait) {
		REDEBUG("'wait' must be enabled to use exec xlat");
		*out = '\0';
		return -1;
	}

	if (inst->input_list) {
		input_pairs = radius_list(request, inst->input_list);
		if (!input_pairs) {
			REDEBUG("Failed to find input pairs for xlat");
			*out = '\0';
			return -1;
		}
	}

	/*
	 *	This function does it's own xlat of the input program
	 *	to execute.
	 */
	result = radius_exec_program(request, fmt, inst->wait, inst->shell_escape,
				     out, outlen, inst->timeout,
				     input_pairs ? *input_pairs : NULL, NULL);
	if (result != 0) {
		out[0] = '\0';
		return -1;
	}

	for (p = out; *p != '\0'; p++) {
		if (*p < ' ') *p = ' ';
	}

	return strlen(out);
}
Ejemplo n.º 20
0
/** De-queue curl requests and wake up the requests that initiated them
 *
 * @param[in] thread	holding the requests to re-enliven.
 * @param[in] mandle	to dequeue curl easy handles/responses from.
 */
static inline void _rest_io_demux(rlm_rest_thread_t *thread, CURLM *mandle)
{
	struct CURLMsg	*m;
	int		msg_queued = 0;

	while ((m = curl_multi_info_read(mandle, &msg_queued))) {
		switch (m->msg) {
		case CURLMSG_DONE:
		{
			REQUEST		*request = NULL;
			CURL		*candle = m->easy_handle;
			CURLcode	ret;

			rad_assert(candle);

			thread->transfers--;

			ret = curl_easy_getinfo(candle, CURLINFO_PRIVATE, &request);
			if (!fr_cond_assert_msg(ret == CURLE_OK,
						"Failed retrieving request data from CURL easy handle (candle)")) {
				curl_multi_remove_handle(mandle, candle);
				return;
			}

			REQUEST_VERIFY(request);

			/*
			 *	If the request failed, say why...
			 */
			if (m->data.result != CURLE_OK) {
				REDEBUG("REST request failed: %s (%i)",
					curl_easy_strerror(m->data.result), m->data.result);
			}

			/*
			 *	Looks like this needs to be done last,
			 *	else m->data.result ends up being junk.
			 */
			curl_multi_remove_handle(mandle, candle);

			unlang_interpret_resumable(request);
		}
			break;

		default:
#ifndef NDEBUG
			DEBUG4("Got unknown msg (%i) when dequeueing curl responses", msg_queued);
#endif
			break;
		}
	}
}
Ejemplo n.º 21
0
int compute_scalar_element(REQUEST *request, pwd_session_t *session, BN_CTX *bn_ctx)
{
	BIGNUM *mask = NULL;
	int ret = -1;

	MEM(session->private_value = BN_new());
	MEM(session->my_element = EC_POINT_new(session->group));
	MEM(session->my_scalar = BN_new());

	MEM(mask = BN_new());

	if (BN_rand_range(session->private_value, session->order) != 1) {
		REDEBUG("Unable to get randomness for private_value");
		goto error;
	}
	if (BN_rand_range(mask, session->order) != 1) {
		REDEBUG("Unable to get randomness for mask");
		goto error;
	}
	BN_add(session->my_scalar, session->private_value, mask);
	BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx);

	if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) {
		REDEBUG("Server element allocation failed");
		goto error;
	}

	if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) {
		REDEBUG("Server element inversion failed");
		goto error;
	}

	ret = 0;

error:
	BN_clear_free(mask);

	return ret;
}
Ejemplo n.º 22
0
static ssize_t xlat_date_convert(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen,
				 void const *mod_inst, UNUSED void const *xlat_inst,
				 REQUEST *request, char const *fmt)
{
	rlm_date_t const *inst = mod_inst;
	struct tm tminfo;
	struct timeval now;
	VALUE_PAIR *vp;

	memset(&tminfo, 0, sizeof(tminfo));

	if (strcmp(fmt, "request") == 0) {
		return date_encode_strftime(out, outlen, inst, request,
					    request->packet->timestamp.tv_sec);
	}

	if (strcmp(fmt, "now") == 0) {
		gettimeofday(&now, NULL);
		return date_encode_strftime(out, outlen, inst, request, now.tv_sec);
	}

	if ((xlat_fmt_get_vp(&vp, request, fmt) < 0) || !vp) return 0;

	switch (vp->vp_type) {
	/*
	 *	These are 'to' types, i.e. we'll convert the integers
	 *	to a time structure, and then output it in the specified
	 *	format as a string.
	 */
	case FR_TYPE_DATE:
		return date_encode_strftime(out, outlen, inst, request, vp->vp_date);

	case FR_TYPE_UINT32:
	case FR_TYPE_UINT64:
		return date_encode_strftime(out, outlen, inst, request, (time_t) vp->vp_uint32);

	/*
	 *	These are 'from' types, i.e. we'll convert the input string
	 *	into a time structure, and then output it as an integer
	 *	unix timestamp.
	 */
	case FR_TYPE_STRING:
		return date_convert_string(request, out, outlen, vp->vp_strvalue, inst->fmt);

	default:
		REDEBUG("Can't convert type %s into date", fr_int2str(fr_value_box_type_names, vp->da->type, "<INVALID>"));
	}

	return -1;
}
Ejemplo n.º 23
0
/** Called when the timeout has expired
 *
 * Marks the request as resumable, and prints the delayed delay time.
 *
 * @param[in] request		The current request.
 * @param[in] instance		This instance of the delay module.
 * @param[in] thread		Thread specific module instance.
 * @param[in] ctx		Scheduled end of the delay.
 * @param[in] fired		When request processing was resumed.
 */
static void _delay_done(REQUEST *request, UNUSED void *instance, UNUSED void *thread, void *ctx, struct timeval *fired)
{
	struct timeval *yielded = talloc_get_type_abort(ctx, struct timeval);

	RDEBUG2("Delay done");

	/*
	 *	timeout should never be *before* the scheduled time,
	 *	if it is, something is very broken.
	 */
	if (!fr_cond_assert(fr_timeval_cmp(fired, yielded) >= 0)) REDEBUG("Unexpected resume time");

	unlang_resumable(request);
}
Ejemplo n.º 24
0
/*
 *	Add raw hex data to the reply.
 */
void eap_add_reply(REQUEST *request,
		   char const *name, uint8_t const *value, int len)
{
	VALUE_PAIR *vp;

	vp = pair_make_reply(name, NULL, T_OP_EQ);
	if (!vp) {
		REDEBUG("Did not create attribute %s: %s\n",
			name, fr_strerror());
		return;
	}

	fr_pair_value_memcpy(vp, value, len);
}
Ejemplo n.º 25
0
/*
 *
 *     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);
}
Ejemplo n.º 26
0
/*
 * send an initial eap-leap request
 * ie access challenge to the user/peer.

 * Frame eap reply packet.
 * len = header + type + leap_methoddata
 * leap_methoddata = value_size + value
 */
static int CC_HINT(nonnull) mod_session_init(UNUSED void *instance, eap_handler_t *handler)
{
	REQUEST 	*request = handler->request;
	leap_session_t	*session;
	leap_packet_t	*reply;

	RDEBUG2("Stage 2");

	/*
	 *	LEAP requires a User-Name attribute
	 */
	if (!handler->request->username) {
		REDEBUG("User-Name is required for EAP-LEAP authentication");
		return 0;
	}

	reply = eapleap_initiate(request, handler->eap_ds, handler->request->username);
	if (!reply) {
		return 0;
	}

	eapleap_compose(request, handler->eap_ds, reply);

	handler->opaque = session = talloc(handler, leap_session_t);
	if (!handler->opaque) {
		talloc_free(reply);
		return 0;
	}

	/*
	 *	Remember which stage we're in, and which challenge
	 *	we sent to the AP.  The later stages will take care
	 *	of filling in the peer response.
	 */
	handler->free_opaque = NULL;

	session->stage = 4;	/* the next stage we're in */
	memcpy(session->peer_challenge, reply->challenge, reply->count);

	REDEBUG2("Successfully initiated");

	/*
	 *	The next stage to process the packet.
	 */
	handler->stage = PROCESS;

	talloc_free(reply);
	return 1;
}
Ejemplo n.º 27
0
/** Process the exit code returned by one of the exec functions
 *
 * @param request Current request.
 * @param answer Output string from exec call.
 * @param len length of data in answer.
 * @param status code returned by exec call.
 * @return One of the RLM_MODULE_* values.
 */
static rlm_rcode_t rlm_exec_status2rcode(REQUEST *request, char *answer, size_t len, int status)
{
	if (status < 0) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Exec'd programs are meant to return exit statuses that correspond
	 *	to the standard RLM_MODULE_* + 1.
	 *
	 *	This frees up 0, for success where it'd normally be reject.
	 */
	if (status == 0) {
		RDEBUG("Program executed successfully");

		return RLM_MODULE_OK;
	}

	if (status > RLM_MODULE_NUMCODES) {
		REDEBUG("Program returned invalid code (greater than max rcode) (%i > %i): %s",
			status, RLM_MODULE_NUMCODES, answer);
		goto fail;

		return RLM_MODULE_FAIL;
	}

	status--;	/* Lets hope no one ever re-enumerates RLM_MODULE_* */

	if (status == RLM_MODULE_FAIL) {
		fail:

		if (len > 0) {
			char *p = &answer[len - 1];

			/*
			 *	Trim off trailing returns
			 */
			while((p > answer) && ((*p == '\r') || (*p == '\n'))) {
				*p-- = '\0';
			}

			module_failure_msg(request, "%s", answer);
		}

		return RLM_MODULE_FAIL;
	}

	return status;
}
Ejemplo n.º 28
0
/** Convert base64 to hex
 *
 * Example: "%{base64tohex:Zm9v}" == "666f6f"
 */
static ssize_t base64_to_hex_xlat(UNUSED void *instance, UNUSED REQUEST *request,
				  char const *fmt, char *out, size_t outlen)
{
	uint8_t decbuf[1024];

	ssize_t declen;
	ssize_t len = strlen(fmt);

	*out = '\0';

	declen = fr_base64_decode(decbuf, sizeof(decbuf), fmt, len);
	if (declen < 0) {
		REDEBUG("Base64 string invalid");
		return -1;
	}

	if ((size_t)((declen * 2) + 1) > outlen) {
		REDEBUG("Base64 conversion failed, output buffer exhausted, needed %zd bytes, have %zd bytes",
			(declen * 2) + 1, outlen);
		return -1;
	}

	return fr_bin2hex(out, decbuf, declen);
}
Ejemplo n.º 29
0
/** Search for and apply an LDAP profile
 * 
 * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common sets of attributes
 * to the request.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
 * @param[in] dn of profile object to apply.
 * @param[in] expanded Structure containing a list of xlat expanded attribute names and mapping information.
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_map_profile(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
			    	 char const *dn, rlm_ldap_map_xlat_t const *expanded)
{
	rlm_rcode_t	rcode = RLM_MODULE_OK;
	ldap_rcode_t	status;
	LDAPMessage	*result = NULL, *entry = NULL;
	int		ldap_errno;
	LDAP		*handle = (*pconn)->handle;
	char		filter[LDAP_MAX_FILTER_STR_LEN];
	
	rad_assert(inst->profile_filter); 	/* We always have a default filter set */

	if (!dn || !*dn) {
		return RLM_MODULE_OK;
	}
	strlcpy(filter, inst->profile_filter, sizeof(filter));

	status = rlm_ldap_search(inst, request, pconn, dn, LDAP_SCOPE_BASE, filter, expanded->attrs, &result);
	switch (status) {
		case LDAP_PROC_SUCCESS:
			break;
		case LDAP_PROC_NO_RESULT:
			RDEBUG("Profile object \"%s\" not found", dn);
			return RLM_MODULE_NOTFOUND;
		default:
			return RLM_MODULE_FAIL;
	}
	
	rad_assert(*pconn);
	rad_assert(result);
	
	entry = ldap_first_entry(handle, result);
	if (!entry) {
		ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
		
		rcode = RLM_MODULE_NOTFOUND;
	 	
	 	goto free_result;
	}
	
	rlm_ldap_map_do(inst, request, handle, expanded, entry);

free_result:
	ldap_msgfree(result);
	
	return rcode;
}
Ejemplo n.º 30
0
rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request,  char const *passcode)
{
	rlm_rcode_t rcode = RLM_MODULE_OK;
	ykclient_rc status;
	ykclient_handle_t *yandle;

	yandle = fr_connection_get(inst->pool);
	if (!yandle) return RLM_MODULE_FAIL;

	/*
	 *	The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
	 *	requests when their easy handle is removed from the multistack.
	 *
	 *	For performance reasons ykclient will stop processing the request immediately after receiving
	 *	a response from one of the servers. If we then immediately call ykclient_handle_cleanup
	 *	the connections are destroyed and will need to be re-established the next time the handle
	 *	is used.
	 *
	 *	To try and prevent this from happening, we leave cleanup until the *next* time
	 *	the handle is used, by which time the requests will of hopefully completed and the connections
	 *	can be re-used.
	 *
	 */
	ykclient_handle_cleanup(yandle);

	status = ykclient_request_process(inst->ykc, yandle, passcode);
	if (status != YKCLIENT_OK) {
		REDEBUG("%s", ykclient_strerror(status));
		switch (status) {
		case YKCLIENT_BAD_OTP:
		case YKCLIENT_REPLAYED_OTP:
			rcode = RLM_MODULE_REJECT;
			break;

		case YKCLIENT_NO_SUCH_CLIENT:
			rcode = RLM_MODULE_NOTFOUND;
			break;

		default:
			rcode = RLM_MODULE_FAIL;
		}
	}

	fr_connection_release(inst->pool, yandle);

	return rcode;
}