Beispiel #1
0
static bool test_free_parent_reparent_child_in_pool(void)
{
	void *top = talloc_new(NULL);
	char *level1;
	char *alternate_level1;
	char *level2;
	void *pool;
	struct new_parent *level3;

	printf("test: free_parent_reparent_child_in_pool\n# "
		"TALLOC FREE PARENT REPARENT CHILD IN POOL\n");

	pool = talloc_pool(top, 1024);
	level1 = talloc_strdup(pool, "level1");
	alternate_level1 = talloc_strdup(top, "alternate_level1");
	level2 = talloc_strdup(level1, "level2");
	level3 = talloc(level2, struct new_parent);
	level3->new_parent = alternate_level1;
	memset(level3->val, 'x', sizeof(level3->val));

	talloc_set_destructor(level3, reparenting_destructor);
	talloc_free(level1);
	talloc_set_destructor(level3, NULL);

	CHECK_PARENT("free_parent_reparent_child_in_pool",
		level3, alternate_level1);

	/* Even freeing alternate_level1 should leave pool alone. */
	talloc_free(alternate_level1);
	talloc_free(top);

	printf("success: free_parent_reparent_child_in_pool\n");
	return true;
}
/** Create thread-specific connections and buffers
 *
 * @param[in] conf	section containing the configuration of this module instance.
 * @param[in] instance	of rlm_logtee_t.
 * @param[in] el	The event list serviced by this thread.
 * @param[in] thread	specific data.
 * @return
 *	- 0 on success.
 *	- -1 on failure.
 */
static int mod_thread_instantiate(UNUSED CONF_SECTION const *conf, void *instance, fr_event_list_t *el, void *thread)
{
	rlm_logtee_t		*inst = talloc_get_type_abort(instance, rlm_logtee_t);
	rlm_logtee_thread_t	*t = talloc_get_type_abort(thread, rlm_logtee_thread_t);

	MEM(t->fring = fr_fring_alloc(t, inst->buffer_depth, false));

	t->inst = inst;
	t->el = el;

	/*
	 *	Pre-allocate temporary attributes
	 */
	MEM(t->msg_pool = talloc_pool(t, 1024));
	MEM(t->msg = fr_pair_afrom_da(t->msg_pool, attr_log_message));
	MEM(t->type = fr_pair_afrom_da(t, attr_log_type));
	MEM(t->lvl = fr_pair_afrom_da(t, attr_log_level));

	/*
	 *	This opens the outbound connection
	 */

	t->conn = fr_connection_alloc(t, el, &inst->connection_timeout, &inst->reconnection_delay,
				      _logtee_conn_init, _logtee_conn_open, _logtee_conn_close,
				      inst->name, t);
	if (t->conn == NULL) return -1;

	fr_connection_signal_init(t->conn);

	return 0;
}
/** Setup an LDAP sync request
 *
 * Allocates a request, with request/reply packets.
 *
 * Sets various fields in the request->packet with information from the file descriptor
 * we received from libldap.
 *
 * @param[in] listen	The common listener encapsulating the libldap fd.
 * @param[in] inst	of the proto_ldap_sync module.
 * @param[in] sync_id 	the unique identifier of the sync.
 * @return
 *	- A new request on success.
 *	- NULL on error.
 */
static REQUEST *proto_ldap_request_setup(rad_listen_t *listen, proto_ldap_inst_t *inst, int sync_id)
{
	TALLOC_CTX		*ctx;
	RADIUS_PACKET		*packet;
	REQUEST			*request;

	ctx = talloc_pool(NULL, main_config->talloc_pool_size);
	if (!ctx) return NULL;
	talloc_set_name_const(ctx, "ldap_inst_pool");

	packet = fr_radius_alloc(ctx, false);
	packet->sockfd = listen->fd;
	packet->id = sync_id;
	packet->src_ipaddr = inst->dst_ipaddr;
	packet->src_port = inst->dst_port;
	packet->dst_ipaddr = inst->src_ipaddr;
	packet->dst_port = inst->src_port;
	gettimeofday(&packet->timestamp, NULL);

	request = request_setup(ctx, listen, packet, inst->client, NULL);
	if (!request) return NULL;

	request->process = request_queued;

	return request;
}
/** Insert a new entry into the data store
 *
 * @param inst main rlm_cache instance.
 * @param request The current request.
 * @param handle Pointer to memcached handle.
 * @param c entry to insert.
 * @return CACHE_OK on success else CACHE_ERROR on error.
 */
static cache_status_t cache_entry_insert(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
					 rlm_cache_entry_t *c)
{
	rlm_cache_memcached_handle_t *mandle = *handle;

	memcached_return_t ret;

	TALLOC_CTX *pool;
	char *to_store;

	pool = talloc_pool(NULL, 1024);
	if (!pool) return CACHE_ERROR;

	if (cache_serialize(pool, &to_store, c) < 0) {
		talloc_free(pool);

		return CACHE_ERROR;
	}

	ret = memcached_set(mandle->handle, c->key, talloc_array_length(c->key) - 1,
		            to_store ? to_store : "",
		            to_store ? talloc_array_length(to_store) - 1 : 0, c->expires, 0);
	talloc_free(pool);
	if (ret != MEMCACHED_SUCCESS) {
		RERROR("Failed storing entry with key \"%s\": %s: %s", c->key,
		       memcached_strerror(mandle->handle, ret),
		       memcached_last_error_message(mandle->handle));

		return CACHE_ERROR;
	}

	return CACHE_OK;
}
Beispiel #5
0
void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
{
	int rcode;
	rlm_sql_t *inst = instance;
	rlm_sql_handle_t *handle;

	/*
	 *	Connections cannot be alloced from the inst or
	 *	pool contexts due to threading issues.
	 */
	handle = talloc_zero(ctx, rlm_sql_handle_t);
	if (!handle) return NULL;

	handle->log_ctx = talloc_pool(handle, 2048);
	if (!handle->log_ctx) {
		talloc_free(handle);
		return NULL;
	}

	/*
	 *	Handle requires a pointer to the SQL inst so the
	 *	destructor has access to the module configuration.
	 */
	handle->inst = inst;

	/*
	 *	When something frees this handle the destructor set by
	 *	the driver will be called first, closing any open sockets.
	 *	Then we call our destructor to trigger an modules.sql.close
	 *	event, then all the memory is freed.
	 */
	talloc_set_destructor(handle, _mod_conn_free);

	rcode = (inst->module->sql_socket_init)(handle, inst->config);
	if (rcode != 0) {
	fail:
		exec_trigger(NULL, inst->cs, "modules.sql.fail", true);

		/*
		 *	Destroy any half opened connections.
		 */
		talloc_free(handle);
		return NULL;
	}

	if (inst->config->connect_query) {
		if (rlm_sql_select_query(inst, NULL, &handle, inst->config->connect_query) != RLM_SQL_OK) goto fail;
		(inst->module->sql_finish_select_query)(handle, inst->config);
	}

	exec_trigger(NULL, inst->cs, "modules.sql.open", false);
	return handle;
}
Beispiel #6
0
static bool test_pool_nest(void)
{
	void *p1, *p2, *p3;
	void *e = talloc_new(NULL);

	p1 = talloc_pool(NULL, 1024);
	torture_assert("talloc_pool", p1 != NULL, "failed");

	p2 = talloc_pool(p1, 500);
	torture_assert("talloc_pool", p2 != NULL, "failed");

	p3 = talloc_size(p2, 10);

	talloc_steal(e, p3);

	talloc_free(p2);

	talloc_free(p3);

	talloc_free(p1);

	return true;
}
Beispiel #7
0
static bool test_pool(void)
{
	void *pool;
	void *p1, *p2, *p3, *p4;

	pool = talloc_pool(NULL, 1024);

	p1 = talloc_size(pool, 80);
	p2 = talloc_size(pool, 20);
	p3 = talloc_size(p1, 50);
	p4 = talloc_size(p3, 1000);

	talloc_free(pool);

	return true;
}
Beispiel #8
0
void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
{
	int rcode;
	rlm_sql_t *inst = instance;
	rlm_sql_handle_t *handle;

	/*
	 *	Connections cannot be alloced from the inst or
	 *	pool contexts due to threading issues.
	 */
	handle = talloc_zero(ctx, rlm_sql_handle_t);
	if (!handle) return NULL;

	handle->log_ctx = talloc_pool(handle, 2048);
	if (!handle->log_ctx) {
		talloc_free(handle);
		return NULL;
	}

	/*
	 *	Handle requires a pointer to the SQL inst so the
	 *	destructor has access to the module configuration.
	 */
	handle->inst = inst;

	rcode = (inst->module->sql_socket_init)(handle, inst->config);
	if (rcode != 0) {
	fail:
		/*
		 *	Destroy any half opened connections.
		 */
		talloc_free(handle);
		return NULL;
	}

	if (inst->config->connect_query) {
		if (rlm_sql_select_query(inst, NULL, &handle, inst->config->connect_query) != RLM_SQL_OK) goto fail;
		(inst->module->sql_finish_select_query)(handle, inst->config);
	}

	return handle;
}
/** Insert a new entry into the data store
 *
 * @copydetails cache_entry_insert_t
 */
static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config, void *driver_inst,
					 REQUEST *request, UNUSED void *handle, const rlm_cache_entry_t *c)
{
	rlm_cache_redis_t	*driver = driver_inst;
	TALLOC_CTX		*pool;

	vp_map_t		*map;

	fr_redis_conn_t		*conn;
	fr_redis_cluster_state_t	state;
	fr_redis_rcode_t	status;
	redisReply		*reply = NULL;
	int			s_ret;

	static char const	command[] = "RPUSH";
	char const		**argv;
	size_t			*argv_len;
	char const		**argv_p;
	size_t			*argv_len_p;

	int			pipelined = 0;	/* How many commands pending in the pipeline */
	redisReply		*replies[5];	/* Should have the same number of elements as pipelined commands */
	size_t			reply_num = 0, i;

	char			*p;
	int			cnt;

	vp_tmpl_t		expires_value;
	vp_map_t		expires = {
					.op	= T_OP_SET,
					.lhs	= &driver->expires_attr,
					.rhs	= &expires_value,
				};

	vp_tmpl_t		created_value;
	vp_map_t		created = {
					.op	= T_OP_SET,
					.lhs	= &driver->created_attr,
					.rhs	= &created_value,
					.next	= &expires
				};

	/*
	 *	Encode the entry created date
	 */
	tmpl_init(&created_value, TMPL_TYPE_DATA, "<TEMP>", 6, T_BARE_WORD);
	created_value.tmpl_data_type = PW_TYPE_DATE;
	created_value.tmpl_data_length = sizeof(created_value.tmpl_data_value.date);
	created_value.tmpl_data_value.date = c->created;

	/*
	 *	Encode the entry expiry time
	 *
	 *	Although Redis objects expire on their own, we still need this
	 *	to ignore entries that were created before the last epoch.
	 */
	tmpl_init(&expires_value, TMPL_TYPE_DATA, "<TEMP>", 6, T_BARE_WORD);
	expires_value.tmpl_data_type = PW_TYPE_DATE;
	expires_value.tmpl_data_length = sizeof(expires_value.tmpl_data_value.date);
	expires_value.tmpl_data_value.date = c->expires;
	expires.next = c->maps;	/* Head of the list */

	for (cnt = 0, map = &created; map; cnt++, map = map->next);

	/*
	 *	The majority of serialized entries should be under 1k.
	 *
	 * @todo We should really calculate this using some sort of moving average.
	 */
	pool = talloc_pool(request, 1024);
	if (!pool) return CACHE_ERROR;

	argv_p = argv = talloc_array(pool, char const *, (cnt * 3) + 2);	/* pair = 3 + cmd + key */
	argv_len_p = argv_len = talloc_array(pool, size_t, (cnt * 3) + 2);	/* pair = 3 + cmd + key */

	*argv_p++ = command;
	*argv_len_p++ = sizeof(command) - 1;

	*argv_p++ = (char const *)c->key;
	*argv_len_p++ = c->key_len;

	/*
	 *	Add the maps to the command string in reverse order
	 */
	for (map = &created; map; map = map->next) {
		if (fr_redis_tuple_from_map(pool, argv_p, argv_len_p, map) < 0) {
			REDEBUG("Failed encoding map as Redis K/V pair");
			talloc_free(pool);
			return CACHE_ERROR;
		}
		argv_p += 3;
		argv_len_p += 3;
	}

	RDEBUG3("Pipelining commands");
	RINDENT();

	for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, c->key, c->key_len, false);
	     s_ret == REDIS_RCODE_TRY_AGAIN;	/* Continue */
	     s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
		/*
		 *	Start the transaction, as we need to set an expiry time too.
		 */
		if (c->expires > 0) {
			RDEBUG3("MULTI");
			if (redisAppendCommand(conn->handle, "MULTI") != REDIS_OK) {
			append_error:
				REXDENT();
				RERROR("Failed appending Redis command to output buffer: %s", conn->handle->errstr);
				talloc_free(pool);
				return CACHE_ERROR;
			}
			pipelined++;
		}

		if (RDEBUG_ENABLED3) {
			p = fr_asprint(request, (char const *)c->key, c->key_len, '\0');
			RDEBUG3("DEL \"%s\"", p);
			talloc_free(p);

		}

		if (redisAppendCommand(conn->handle, "DEL %b", c->key, c->key_len) != REDIS_OK) goto append_error;
		pipelined++;

		if (RDEBUG_ENABLED3) {
			RDEBUG3("argv command");
			RINDENT();
			for (i = 0; i < talloc_array_length(argv); i++) {
				p = fr_asprint(request, argv[i], argv_len[i], '\0');
				RDEBUG3("%s", p);
				talloc_free(p);
			}
			REXDENT();
		}
		redisAppendCommandArgv(conn->handle, talloc_array_length(argv), argv, argv_len);
		pipelined++;

		/*
		 *	Set the expiry time and close out the transaction.
		 */
		if (c->expires > 0) {
			if (RDEBUG_ENABLED3) {
				p = fr_asprint(request, (char const *)c->key, c->key_len, '\"');
				RDEBUG3("EXPIREAT \"%s\" %li", p, (long)c->expires);
				talloc_free(p);
			}
			if (redisAppendCommand(conn->handle, "EXPIREAT %b %i", c->key,
					       c->key_len, c->expires) != REDIS_OK) goto append_error;
			pipelined++;
			RDEBUG3("EXEC");
			if (redisAppendCommand(conn->handle, "EXEC") != REDIS_OK) goto append_error;
			pipelined++;
		}
		REXDENT();

		reply_num = fr_redis_pipeline_result(&status, replies, sizeof(replies) / sizeof(*replies),
						     conn, pipelined);
		reply = replies[0];
	}
	talloc_free(pool);

	if (s_ret != REDIS_RCODE_SUCCESS) {
		RERROR("Failed inserting entry");
		return CACHE_ERROR;
	}

	RDEBUG3("Command results");
	RINDENT();
	for (i = 0; i < reply_num; i++) {
		fr_redis_reply_print(L_DBG_LVL_3, replies[i], request, i);
		fr_redis_reply_free(replies[i]);
	}
	REXDENT();

	return CACHE_OK;
}

/** Call delete the cache entry from redis
 *
 * @copydetails cache_entry_expire_t
 */
static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *driver_inst,
					 REQUEST *request, UNUSED void *handle,  uint8_t const *key, size_t key_len)
{
	rlm_cache_redis_t		*driver = driver_inst;
	fr_redis_cluster_state_t	state;
	fr_redis_conn_t			*conn;
	fr_redis_rcode_t			status;
	redisReply			*reply = NULL;
	int				s_ret;

	for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false);
	     s_ret == REDIS_RCODE_TRY_AGAIN;	/* Continue */
	     s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
	     	reply = redisCommand(conn->handle, "DEL %b", key, key_len);
	     	status = fr_redis_command_status(conn, reply);
	}
	if (s_ret != REDIS_RCODE_SUCCESS) {
		RERROR("Failed expiring entry");
		fr_redis_reply_free(reply);
		return CACHE_ERROR;
	}

	rad_assert(reply);	/* clang scan */
	if (reply->type == REDIS_REPLY_INTEGER) {
		fr_redis_reply_free(reply);
		if (reply->integer) return CACHE_OK;	/* Affected */
		return CACHE_MISS;
	}

	REDEBUG("Bad result type, expected integer, got %s",
		fr_int2str(redis_reply_types, reply->type, "<UNKNOWN>"));
	fr_redis_reply_free(reply);

	return CACHE_ERROR;
}

extern cache_driver_t rlm_cache_redis;
cache_driver_t rlm_cache_redis = {
	.name		= "rlm_cache_redis",
	.instantiate	= mod_instantiate,
	.inst_size	= sizeof(rlm_cache_redis_t),
	.free		= cache_entry_free,

	.find		= cache_entry_find,
	.insert		= cache_entry_insert,
	.expire		= cache_entry_expire,
};
/** Handle authorization requests using Couchbase document data
 *
 * Attempt to fetch the document assocaited with the requested user by
 * using the deterministic key defined in the configuration.  When a valid
 * document is found it will be parsed and the containing value pairs will be
 * injected into the request.
 *
 * @param instance	The module instance.
 * @param thread	specific data.
 * @param request	The authorization request.
 * @return Operation status (#rlm_rcode_t).
 */
static rlm_rcode_t mod_authorize(void *instance, UNUSED void *thread, REQUEST *request)
{
	rlm_couchbase_t const	*inst = instance;		/* our module instance */
	rlm_couchbase_handle_t	*handle = NULL;			/* connection pool handle */
	char			buffer[MAX_KEY_SIZE];
	char const		*dockey;			/* our document key */
	lcb_error_t		cb_error = LCB_SUCCESS;		/* couchbase error holder */
	rlm_rcode_t		rcode = RLM_MODULE_OK;		/* return code */
	ssize_t			slen;

	/* assert packet as not null */
	rad_assert(request->packet != NULL);

	/* attempt to build document key */
	slen = tmpl_expand(&dockey, buffer, sizeof(buffer), request, inst->user_key, NULL, NULL);
	if (slen < 0) return RLM_MODULE_FAIL;
	if ((dockey == buffer) && is_truncated((size_t)slen, sizeof(buffer))) {
		REDEBUG("Key too long, expected < " STRINGIFY(sizeof(buffer)) " bytes, got %zi bytes", slen);
		return RLM_MODULE_FAIL;
	}

	/* get handle */
	handle = fr_pool_connection_get(inst->pool, request);

	/* check handle */
	if (!handle) return RLM_MODULE_FAIL;

	/* set couchbase instance */
	lcb_t cb_inst = handle->handle;

	/* set cookie */
	cookie_t *cookie = handle->cookie;

	/* fetch document */
	cb_error = couchbase_get_key(cb_inst, cookie, dockey);

	/* check error */
	if (cb_error != LCB_SUCCESS || !cookie->jobj) {
		/* log error */
		RERROR("failed to fetch document or parse return");
		/* set return */
		rcode = RLM_MODULE_FAIL;
		/* return */
		goto finish;
	}

	/* debugging */
	RDEBUG3("parsed user document == %s", json_object_to_json_string(cookie->jobj));

	{
		TALLOC_CTX	*pool = talloc_pool(request, 1024);	/* We need to do lots of allocs */
		fr_cursor_t	maps, vlms;
		vp_map_t	*map_head = NULL, *map;
		vp_list_mod_t	*vlm_head = NULL, *vlm;

		fr_cursor_init(&maps, &map_head);

		/*
		 *	Convert JSON data into maps
		 */
		if ((mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_CONTROL) < 0) ||
		    (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_REPLY) < 0) ||
		    (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_REQUEST) < 0) ||
		    (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_STATE) < 0)) {
		invalid:
			talloc_free(pool);
			rcode = RLM_MODULE_INVALID;
			goto finish;
		}

		fr_cursor_init(&vlms, &vlm_head);

		/*
		 *	Convert all the maps into list modifications,
		 *	which are guaranteed to succeed.
		 */
		for (map = fr_cursor_head(&maps);
		     map;
		     map = fr_cursor_next(&maps)) {
			if (map_to_list_mod(pool, &vlm, request, map, NULL, NULL) < 0) goto invalid;
			fr_cursor_insert(&vlms, vlm);
		}

		if (!vlm_head) {
			RDEBUG2("Nothing to update");
			talloc_free(pool);
			rcode = RLM_MODULE_NOOP;
			goto finish;
		}

		/*
		 *	Apply the list of modifications
		 */
		for (vlm = fr_cursor_head(&vlms);
		     vlm;
		     vlm = fr_cursor_next(&vlms)) {
			int ret;

			ret = map_list_mod_apply(request, vlm);	/* SHOULD NOT FAIL */
			if (!fr_cond_assert(ret == 0)) {
				talloc_free(pool);
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}
		}

		talloc_free(pool);
	}

finish:
	/* free json object */
	if (cookie->jobj) {
		json_object_put(cookie->jobj);
		cookie->jobj = NULL;
	}

	/* release handle */
	if (handle) fr_pool_connection_release(inst->pool, request, handle);

	/* return */
	return rcode;
}
Beispiel #11
0
/** Create and insert a cache entry
 *
 * @return
 *	- #RLM_MODULE_OK on success.
 *	- #RLM_MODULE_UPDATED if we merged the cache entry.
 *	- #RLM_MODULE_FAIL on failure.
 */
static rlm_rcode_t cache_insert(rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle,
				uint8_t const *key, size_t key_len, int ttl)
{
	vp_map_t		const *map;
	vp_map_t		**last, *c_map;

	VALUE_PAIR		*vp;
	bool			merge = false;
	rlm_cache_entry_t	*c;
	size_t			len;

	TALLOC_CTX		*pool;

	if ((inst->config.max_entries > 0) && inst->driver->count &&
	    (inst->driver->count(&inst->config, inst->driver_inst->data, request, handle) > inst->config.max_entries)) {
		RWDEBUG("Cache is full: %d entries", inst->config.max_entries);
		return RLM_MODULE_FAIL;
	}

	c = cache_alloc(inst, request);
	if (!c) return RLM_MODULE_FAIL;

	c->key = talloc_memdup(c, key, key_len);
	c->key_len = key_len;
	c->created = c->expires = request->packet->timestamp.tv_sec;
	c->expires += ttl;

	last = &c->maps;

	RDEBUG2("Creating new cache entry");

	/*
	 *	Alloc a pool so we don't have excessive allocs when
	 *	gathering VALUE_PAIRs to cache.
	 */
	pool = talloc_pool(NULL, 2048);
	for (map = inst->maps; map != NULL; map = map->next) {
		VALUE_PAIR	*to_cache = NULL;
		fr_cursor_t	cursor;

		rad_assert(map->lhs && map->rhs);

		/*
		 *	Calling map_to_vp gives us exactly the same result,
		 *	as if this were an update section.
		 */
		if (map_to_vp(pool, &to_cache, request, map, NULL) < 0) {
			RDEBUG2("Skipping %s", map->rhs->name);
			continue;
		}

		for (vp = fr_cursor_init(&cursor, &to_cache);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			/*
			 *	Prevent people from accidentally caching
			 *	cache control attributes.
			 */
			if (map->rhs->type == TMPL_TYPE_LIST) switch (vp->da->attr) {
			case FR_CACHE_TTL:
			case FR_CACHE_STATUS_ONLY:
			case FR_CACHE_MERGE_NEW:
			case FR_CACHE_ENTRY_HITS:
				RDEBUG2("Skipping %s", vp->da->name);
				continue;

			default:
				break;
			}

			RINDENT();
			if (RDEBUG_ENABLED2) map_debug_log(request, map, vp);
			REXDENT();

			MEM(c_map = talloc_zero(c, vp_map_t));
			c_map->op = map->op;

			/*
			 *	Now we turn the VALUE_PAIRs into maps.
			 */
			switch (map->lhs->type) {
			/*
			 *	Attributes are easy, reuse the LHS, and create a new
			 *	RHS with the fr_value_box_t from the VALUE_PAIR.
			 */
			case TMPL_TYPE_ATTR:
				c_map->lhs = map->lhs;	/* lhs shouldn't be touched, so this is ok */
			do_rhs:
				MEM(c_map->rhs = tmpl_init(talloc(c_map, vp_tmpl_t),
							   TMPL_TYPE_DATA, map->rhs->name, map->rhs->len, T_BARE_WORD));
				if (fr_value_box_copy(c_map->rhs, &c_map->rhs->tmpl_value, &vp->data) < 0) {
					REDEBUG("Failed copying attribute value");
				error:
					talloc_free(pool);
					talloc_free(c);
					return RLM_MODULE_FAIL;
				}
				c_map->rhs->tmpl_value_type = vp->vp_type;
				if (vp->vp_type == FR_TYPE_STRING) {
					c_map->rhs->quote = is_printable(vp->vp_strvalue, vp->vp_length) ?
						T_SINGLE_QUOTED_STRING : T_DOUBLE_QUOTED_STRING;
				}
				break;

			/*
			 *	Lists are weird... We need to fudge a new LHS template,
			 *	which is a combination of the LHS list and the attribute.
			 */
			case TMPL_TYPE_LIST:
			{
				char attr[256];

				MEM(c_map->lhs = tmpl_init(talloc(c_map, vp_tmpl_t),
							   TMPL_TYPE_ATTR, map->lhs->name, map->lhs->len, T_BARE_WORD));
				c_map->lhs->tmpl_da = vp->da;
				if (vp->da->flags.is_unknown) { /* for tmpl_verify() */
					c_map->lhs->tmpl_unknown = fr_dict_unknown_acopy(c_map->lhs, vp->da);
					c_map->lhs->tmpl_da = c_map->lhs->tmpl_unknown;
				}

				c_map->lhs->tmpl_tag = vp->tag;
				c_map->lhs->tmpl_list = map->lhs->tmpl_list;
				c_map->lhs->tmpl_num = map->lhs->tmpl_num;
				c_map->lhs->tmpl_request = map->lhs->tmpl_request;

				/*
				 *	We need to rebuild the attribute name, to be the
				 *	one we copied from the source list.
				 */
				len = tmpl_snprint(attr, sizeof(attr), c_map->lhs);
				if (is_truncated(len, sizeof(attr))) {
					REDEBUG("Serialized attribute too long.  Must be < "
						STRINGIFY(sizeof(attr)) " bytes, got %zu bytes", len);
					goto error;
				}
				c_map->lhs->len = len;
				c_map->lhs->name = talloc_typed_strdup(c_map->lhs, attr);
			}
				goto do_rhs;

			default:
				rad_assert(0);
			}
			*last = c_map;
			last = &(*last)->next;
		}
		talloc_free_children(pool); /* reset pool state */
	}
	talloc_free(pool);

	/*
	 *	Check to see if we need to merge the entry into the request
	 */
	vp = fr_pair_find_by_da(request->control, attr_cache_merge_new, TAG_ANY);
	if (vp && vp->vp_bool) merge = true;

	if (merge) cache_merge(inst, request, c);

	for (;;) {
		cache_status_t ret;

		ret = inst->driver->insert(&inst->config, inst->driver_inst->data, request, *handle, c);
		switch (ret) {
		case CACHE_RECONNECT:
			if (cache_reconnect(handle, inst, request) == 0) continue;
			return RLM_MODULE_FAIL;

		case CACHE_OK:
			RDEBUG2("Committed entry, TTL %d seconds", ttl);
			cache_free(inst, &c);
			return merge ? RLM_MODULE_UPDATED :
				       RLM_MODULE_OK;

		default:
			talloc_free(c);	/* Failed insertion - use talloc_free not the driver free */
			return RLM_MODULE_FAIL;
		}
	}
}
Beispiel #12
0
int bts_main(int argc, char **argv)
{
	struct gsm_bts_role_bts *btsb;
	struct gsm_bts_trx *trx;
	struct e1inp_line *line;
	void *tall_msgb_ctx;
	int rc, i;

	printf("((*))\n  |\n / \\ OsmoBTS\n");

	tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
	tall_msgb_ctx = talloc_pool(tall_bts_ctx, 100*1024);
	msgb_set_talloc_ctx(tall_msgb_ctx);

	bts_log_init(NULL);

	handle_options(argc, argv);

	bts = gsm_bts_alloc(tall_bts_ctx);
	if (!bts) {
		fprintf(stderr, "Failed to create BTS structure\n");
		exit(1);
	}
	for (i = 1; i < trx_num; i++) {
		trx = gsm_bts_trx_alloc(bts);
		if (!trx) {
			fprintf(stderr, "Failed to create TRX structure\n");
			exit(1);
		}
	}
	vty_init(&bts_vty_info);
	e1inp_vty_init();
	bts_vty_init(bts, &bts_log_info);

	/* enable realtime priority for us */
	if (rt_prio != -1) {
		struct sched_param param;

		memset(&param, 0, sizeof(param));
		param.sched_priority = rt_prio;
		rc = sched_setscheduler(getpid(), SCHED_RR, &param);
		if (rc != 0) {
			fprintf(stderr, "Setting SCHED_RR priority(%d) failed: %s\n",
				param.sched_priority, strerror(errno));
			exit(1);
		}
	}

        if (gsmtap_ip) {
		gsmtap = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 1);
		if (!gsmtap) {
			fprintf(stderr, "Failed during gsmtap_init()\n");
			exit(1);
		}
		gsmtap_source_add_sink(gsmtap);
	}

	if (bts_init(bts) < 0) {
		fprintf(stderr, "unable to open bts\n");
		exit(1);
	}

	abis_init(bts);

	rc = vty_read_config_file(config_file, NULL);
	if (rc < 0) {
		fprintf(stderr, "Failed to parse the config file: '%s'\n",
			config_file);
		exit(1);
	}

	write_pid_file("osmo-bts");

	bts_controlif_setup(bts);

	rc = telnet_init(tall_bts_ctx, NULL, OSMO_VTY_PORT_BTS);
	if (rc < 0) {
		fprintf(stderr, "Error initializing telnet\n");
		exit(1);
	}

	if (pcu_sock_init()) {
		fprintf(stderr, "PCU L1 socket failed\n");
		exit(1);
	}

	signal(SIGINT, &signal_handler);
	//signal(SIGABRT, &signal_handler);
	signal(SIGUSR1, &signal_handler);
	signal(SIGUSR2, &signal_handler);
	osmo_init_ignore_signals();

	btsb = bts_role_bts(bts);
	if (!btsb->bsc_oml_host) {
		fprintf(stderr, "Cannot start BTS without knowing BSC OML IP\n");
		exit(1);
	}

	line = abis_open(bts, btsb->bsc_oml_host, "sysmoBTS");
	if (!line) {
		fprintf(stderr, "unable to connect to BSC\n");
		exit(2);
	}

	if (daemonize) {
		rc = osmo_daemonize();
		if (rc < 0) {
			perror("Error during daemonize");
			exit(1);
		}
	}

	while (quit < 2) {
		log_reset_context();
		osmo_select_main(0);
	}

	return EXIT_SUCCESS;
}
Beispiel #13
0
/** Convert group membership information into attributes
 *
 * @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] entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
 * @param[in] attr membership attribute to look for in the entry.
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_cacheable_userobj(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
				       LDAPMessage *entry, char const *attr)
{
	rlm_rcode_t rcode = RLM_MODULE_OK;

	struct berval **values;
	size_t value_len = 0;
	TALLOC_CTX *value_pool;

	char *group_name[LDAP_MAX_CACHEABLE + 1];
	char **name_p = group_name;

	char *group_dn[LDAP_MAX_CACHEABLE + 1];
	char **dn_p;

	char *name;

	VALUE_PAIR *vp, **vps;
	TALLOC_CTX *ctx;
	vp_cursor_t cursor;

	int is_dn, i, count;

	rad_assert(entry);
	rad_assert(attr);

	/*
	 *	Parse the membership information we got in the initial user query.
	 */
	values = ldap_get_values_len((*pconn)->handle, entry, attr);
	if (!values) {
		RDEBUG2("No cacheable group memberships found in user object");

		return RLM_MODULE_OK;
	}
	count = ldap_count_values_len(values);

	vps = radius_list(request, PAIR_LIST_CONTROL);
	ctx = radius_list_ctx(request, PAIR_LIST_CONTROL);
	fr_cursor_init(&cursor, vps);

	/*
	 *	Avoid allocing buffers for each value.
	 *
	 *	The old code used ldap_get_values, which was likely doing
	 *	a very similar thing internally to produce \0 terminated
	 *	buffers from bervalues.
	 */
	for (i = 0; (i < LDAP_MAX_CACHEABLE) && (i < count); i++) value_len += values[i]->bv_len + 1;
	value_pool = talloc_pool(request, value_len);

	for (i = 0; (i < LDAP_MAX_CACHEABLE) && (i < count); i++) {
		is_dn = rlm_ldap_is_dn(values[i]->bv_val, values[i]->bv_len);

		if (inst->cacheable_group_dn) {
			/*
			 *	The easy case, we're caching DNs and we got a DN.
			 */
			if (is_dn) {
				MEM(vp = pairalloc(ctx, inst->cache_da));
				pairstrncpy(vp, values[i]->bv_val, values[i]->bv_len);
				fr_cursor_insert(&cursor, vp);

				RDEBUG("Added %s with value \"%s\" to control list", inst->cache_da->name,
				       vp->vp_strvalue);
			/*
			 *	We were told to cache DNs but we got a name, we now need to resolve
			 *	this to a DN. Store all the group names in an array so we can do one query.
			 */
			} else {
				*name_p++ = rlm_ldap_berval_to_string(value_pool, values[i]);
			}
		}

		if (inst->cacheable_group_name) {
			/*
			 *	The easy case, we're caching names and we got a name.
			 */
			if (!is_dn) {
				MEM(vp = pairalloc(ctx, inst->cache_da));
				pairstrncpy(vp, values[i]->bv_val, values[i]->bv_len);
				fr_cursor_insert(&cursor, vp);

				RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name,
				       vp->vp_strvalue);
			/*
			 *	We were told to cache names but we got a DN, we now need to resolve
			 *	this to a name.
			 *	Only Active Directory supports filtering on DN, so we have to search
			 *	for each individual group.
			 */
			} else {
				char *dn;

				dn = rlm_ldap_berval_to_string(value_pool, values[i]);
				rcode = rlm_ldap_group_dn2name(inst, request, pconn, dn, &name);
				talloc_free(dn);
				if (rcode != RLM_MODULE_OK) {
					ldap_value_free_len(values);
					talloc_free(value_pool);

					return rcode;
				}

				MEM(vp = pairalloc(ctx, inst->cache_da));
				pairstrncpy(vp, name, talloc_array_length(name) - 1);
				fr_cursor_insert(&cursor, vp);

				RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, name);
				talloc_free(name);
			}
		}
	}
	*name_p = NULL;

	rcode = rlm_ldap_group_name2dn(inst, request, pconn, group_name, group_dn, sizeof(group_dn));

	ldap_value_free_len(values);
	talloc_free(value_pool);

	if (rcode != RLM_MODULE_OK) return rcode;

	dn_p = group_dn;
	while (*dn_p) {
		MEM(vp = pairalloc(ctx, inst->cache_da));
		pairstrcpy(vp, *dn_p);
		fr_cursor_insert(&cursor, vp);

		RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, *dn_p);
		ldap_memfree(*dn_p);

		dn_p++;
	}

	return rcode;
}
Beispiel #14
0
void do_db( struct configuration_data *config, char *dbstring)
{
	int rc;
	int try;
	const char *error;
	dbi_result result;
	/**
	 * a NULL dbstring? May happen when a R/W VFS function
	 * hat 0 bytes to transfer. This data is not relevant
	 * for statistics.
	 */
	if (dbstring == NULL) return;
	/** 
	 * Check if the connection is alive. We try ten times
	 * to restore the connection if not
	 */
	for (try = 0; try < 10; try++) {
		rc = dbi_conn_ping( config->DBIconn );
		if (rc == 1) {
			result = dbi_conn_query(config->DBIconn, dbstring);
			if (result == NULL) {
				dbi_conn_error(config->DBIconn,&error);
				syslog(LOG_DEBUG,"DBI ERROR: %s",error);
				rc = 0;}
			else break;
		}
	}
	if (rc == 0 ) {
		syslog(LOG_DEBUG, "ERROR: Database handling error!");
		return;
	}
	dbi_result_free(result);
}

void cleanup_cache( TALLOC_CTX *ctx,struct configuration_data *config,
	struct cache_entry *entry)
{
	char *dbstring;
	struct cache_entry *go = entry;
	struct cache_entry *backup;
	struct cache_entry *backup2 = NULL;
	struct cache_entry *down =NULL;
	// left
	go = go->left;
	while (go != NULL) {
		backup = go->left;
		dbstring = cache_create_database_string(ctx,go,config);
		do_db(config,dbstring);
		talloc_free(dbstring);
		// go down
		down = go->down;
		while (down != NULL) {
			backup2 = down->down;
			dbstring = cache_create_database_string(ctx,down,config);
			do_db(config,dbstring);
			talloc_free(dbstring);
			talloc_free(down);
			down = backup2;
		}
		talloc_free(go);
		go = backup;
	}
	// right
	go = entry->right;
        while (go != NULL) {
                backup = go->right;
                dbstring = cache_create_database_string(ctx,go,config);
                do_db(config,dbstring);
		talloc_free(dbstring);
                // go down
                down = go->down;
                while (down != NULL) { 
                        backup2 = down->down;
                        dbstring = cache_create_database_string(ctx,down,config);
                        do_db(config,dbstring);
                        talloc_free(dbstring);
                        talloc_free(down);
                        down = backup2;
                }
                talloc_free(go);
                go = backup;
        }
	// other_ops
	go = entry->other_ops;
	while (go != NULL) {
		backup = go->other_ops;
		dbstring = cache_create_database_string(ctx,go,config);
		do_db(config,dbstring);
		talloc_free(dbstring);
		talloc_free(go);
		go = backup;
	}
	// delete tree begin
	dbstring = cache_create_database_string(ctx,entry,config);
	do_db(config,dbstring);
	if (dbstring != NULL) talloc_free(dbstring);
	talloc_free(entry);
}	
	
	


/*
 * cache_manager runs as a detached thread. Every half second,
 * it's checking if there's data available to store to the DB.
 * in case of yes, it walks through the list of data, enables
 * a new cache, and stores the data in the DB
 */
void cache_manager(struct configuration_data *config )
{
	int maintenance_c_val;
	if (config->precision>0)
		maintenance_c_val = config->maintenance_seconds / config->precision;
	else maintenance_c_val = config->maintenance_seconds;

	int maintenance_count = 0;
        pthread_detach(pthread_self());
	/* backup the start and make it possible to
	 * allocate a new cache beginning
	 */
	while (1 == 1) {
		if (config->precision != 0) sleep(config->precision);
		else sleep(5);
		maintenance_count++;
        	pthread_mutex_lock(&cache_mutex);
		struct cache_entry *backup = cache_start;
		TALLOC_CTX *dbpool = talloc_pool(NULL,2048);
       		cache_start = NULL;
        	cache_end = NULL;
		pthread_mutex_unlock(&cache_mutex);
		if (backup != NULL) {
			/* store all existing entries into the database */
			do_db(config,"BEGIN TRANSACTION;");
			cleanup_cache( dbpool,config,backup);
			do_db(config,"COMMIT;");
		}
		talloc_free(dbpool);

		if (maintenance_count == maintenance_c_val) {
			char String[400];
			char dbstring[300];
			struct tm *tm;
			do_db(config,"BEGIN TRANSACTION;");
		        time_t today=time(NULL);
		        time_t delete_date=today - config->maint_run_time;
		        tm = localtime ( &delete_date );


		        sprintf(String,"%04d-%02d-%02d %02d:%02d:%02d", \
               			tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, \
               			tm->tm_hour, tm->tm_min, tm->tm_sec);


       			strcpy(dbstring,"delete from data where timestamp < '");
       			strcat(dbstring,String);
       			strcat(dbstring,"';");
			do_db(config,dbstring);
			do_db(config,"COMMIT;");
			maintenance_count = 0;
		}
				


			
		
	}
}
Beispiel #15
0
static bool test_pool(void)
{
	void *pool;
	void *p1, *p2, *p3, *p4;
	void *p2_2;

	pool = talloc_pool(NULL, 1024);

	p1 = talloc_size(pool, 80);
	memset(p1, 0x11, talloc_get_size(p1));
	p2 = talloc_size(pool, 20);
	memset(p2, 0x11, talloc_get_size(p2));
	p3 = talloc_size(p1, 50);
	memset(p3, 0x11, talloc_get_size(p3));
	p4 = talloc_size(p3, 1000);
	memset(p4, 0x11, talloc_get_size(p4));

#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
	p2_2 = talloc_realloc_size(pool, p2, 20+1);
	torture_assert("pool realloc 20+1", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));
	p2_2 = talloc_realloc_size(pool, p2, 20-1);
	torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));
	p2_2 = talloc_realloc_size(pool, p2, 20-1);
	torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));

	talloc_free(p3);

	/* this should reclaim the memory of p4 and p3 */
	p2_2 = talloc_realloc_size(pool, p2, 400);
	torture_assert("pool realloc 400", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));

	talloc_free(p1);

	/* this should reclaim the memory of p1 */
	p2_2 = talloc_realloc_size(pool, p2, 800);
	torture_assert("pool realloc 800", p2_2 == p1, "failed: pointer not changed");
	p2 = p2_2;
	memset(p2, 0x11, talloc_get_size(p2));

	/* this should do a malloc */
	p2_2 = talloc_realloc_size(pool, p2, 1800);
	torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
	p2 = p2_2;
	memset(p2, 0x11, talloc_get_size(p2));

	/* this should reclaim the memory from the pool */
	p3 = talloc_size(pool, 80);
	torture_assert("pool alloc 80", p3 == p1, "failed: pointer changed");
	memset(p3, 0x11, talloc_get_size(p3));

	talloc_free(p2);
	talloc_free(p3);

	p1 = talloc_size(pool, 80);
	memset(p1, 0x11, talloc_get_size(p1));
	p2 = talloc_size(pool, 20);
	memset(p2, 0x11, talloc_get_size(p2));

	talloc_free(p1);

	p2_2 = talloc_realloc_size(pool, p2, 20-1);
	torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));
	p2_2 = talloc_realloc_size(pool, p2, 20-1);
	torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
	memset(p2, 0x11, talloc_get_size(p2));

	/* this should do a malloc */
	p2_2 = talloc_realloc_size(pool, p2, 1800);
	torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
	p2 = p2_2;
	memset(p2, 0x11, talloc_get_size(p2));

	/* this should reclaim the memory from the pool */
	p3 = talloc_size(pool, 800);
	torture_assert("pool alloc 800", p3 == p1, "failed: pointer changed");
	memset(p3, 0x11, talloc_get_size(p3));

#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */

	talloc_free(pool);

	return true;
}
Beispiel #16
0
/** Converts a serialized cache entry back into a structure
 *
 * @param c Cache entry to populate (should already be allocated)
 * @param in String representation of cache entry.
 * @param inlen Length of string. May be < 0 in which case strlen will be
 *	used to calculate the length of the string.
 * @return 0 on success, -1 on error.
 */
int cache_deserialize(rlm_cache_entry_t *c, char *in, ssize_t inlen)
{
	vp_cursor_t packet, control, reply;

	TALLOC_CTX *store = NULL;
	char *p, *q;

	store = talloc_pool(c, 1024);
	if (!store) return -1;

	if (inlen < 0) inlen = strlen(in);

	fr_cursor_init(&packet, &c->packet);
	fr_cursor_init(&control, &c->control);
	fr_cursor_init(&reply, &c->reply);

	p = in;

	while (((size_t)(p - in)) < (size_t)inlen) {
		value_pair_map_t *map = NULL;
		VALUE_PAIR *vp = NULL;
		ssize_t len;

		q = strchr(p, '\n');
		if (!q) break;	/* List should also be terminated with a \n */
		*q = '\0';

		if (map_afrom_attr_str(store, &map, p,
				       REQUEST_CURRENT, PAIR_LIST_REQUEST,
				       REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
			fr_strerror_printf("Failed parsing pair: %s", p);
			goto error;
		}

		if (map->lhs->type != TMPL_TYPE_ATTR) {
			fr_strerror_printf("Pair left hand side \"%s\" parsed as %s, needed attribute.  "
					   "Check local dictionaries", map->lhs->name,
					   fr_int2str(tmpl_names, map->lhs->type, "<INVALID>"));
			goto error;
		}

		if (map->rhs->type != TMPL_TYPE_LITERAL) {
			fr_strerror_printf("Pair right hand side \"%s\" parsed as %s, needed literal.  "
					   "Check serialized data quoting", map->rhs->name,
					   fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
			goto error;
		}

		/*
		 *	Convert literal to a type appropriate for
		 *	the VP.
		 */
		if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) goto error;

		vp = pairalloc(c, map->lhs->tmpl_da);
		len = value_data_copy(vp, &vp->data, map->rhs->tmpl_data_type,
				      &map->rhs->tmpl_data_value, map->rhs->tmpl_data_length);
		if (len < 0) goto error;

		/*
		 *	Pull out the special attributes, and set the
		 *	relevant cache entry fields.
		 */
		if (vp->da->vendor == 0) switch (vp->da->attr) {
		case PW_CACHE_CREATED:
			c->created = vp->vp_date;
			talloc_free(vp);
			goto next;

		case PW_CACHE_EXPIRES:
			c->expires = vp->vp_date;
			talloc_free(vp);
			goto next;

		default:
			break;
		}

		switch (map->lhs->tmpl_list) {
		case PAIR_LIST_REQUEST:
			fr_cursor_insert(&packet, vp);
			break;

		case PAIR_LIST_CONTROL:
			fr_cursor_insert(&control, vp);
			break;

		case PAIR_LIST_REPLY:
			fr_cursor_insert(&reply, vp);
			break;

		default:
			fr_strerror_printf("Invalid cache list for pair: %s", p);
		error:
			talloc_free(vp);
			talloc_free(map);
			return -1;
		}
	next:
		p = q + 1;
		talloc_free(map);
	}

	return 0;
}
Beispiel #17
0
static bool test_pool_steal(void)
{
	void *root;
	void *pool;
	void *p1, *p2;
	void *p1_2, *p2_2;
	size_t hdr;
	size_t ofs1, ofs2;

	root = talloc_new(NULL);
	pool = talloc_pool(root, 1024);

	p1 = talloc_size(pool, 4 * 16);
	torture_assert("pool allocate 4 * 16", p1 != NULL, "failed ");
	memset(p1, 0x11, talloc_get_size(p1));
	p2 = talloc_size(pool, 4 * 16);
	torture_assert("pool allocate 4 * 16", p2 > p1, "failed: !(p2 > p1) ");
	memset(p2, 0x11, talloc_get_size(p2));

	ofs1 = PTR_DIFF(p2, p1);
	hdr = ofs1 - talloc_get_size(p1);

	talloc_steal(root, p1);
	talloc_steal(root, p2);

	talloc_free(pool);

	p1_2 = p1;

#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
	p1_2 = talloc_realloc_size(root, p1, 5 * 16);
	torture_assert("pool realloc 5 * 16", p1_2 > p2, "failed: pointer not changed");
	memset(p1_2, 0x11, talloc_get_size(p1_2));
	ofs1 = PTR_DIFF(p1_2, p2);
	ofs2 = talloc_get_size(p2) + hdr;

	torture_assert("pool realloc ", ofs1 == ofs2, "failed: pointer offset unexpected");

	p2_2 = talloc_realloc_size(root, p2, 3 * 16);
	torture_assert("pool realloc 5 * 16", p2_2 == p2, "failed: pointer changed");
	memset(p2_2, 0x11, talloc_get_size(p2_2));
#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */

	talloc_free(p1_2);

	p2_2 = p2;

#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
	/* now we should reclaim the full pool */
	p2_2 = talloc_realloc_size(root, p2, 8 * 16);
	torture_assert("pool realloc 8 * 16", p2_2 == p1, "failed: pointer not expected");
	p2 = p2_2;
	memset(p2_2, 0x11, talloc_get_size(p2_2));

	/* now we malloc and free the full pool space */
	p2_2 = talloc_realloc_size(root, p2, 2 * 1024);
	torture_assert("pool realloc 2 * 1024", p2_2 != p1, "failed: pointer not expected");
	memset(p2_2, 0x11, talloc_get_size(p2_2));

#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */

	talloc_free(p2_2);

	talloc_free(root);

	return true;
}
Beispiel #18
0
/** Serialize a cache entry as a humanly readable string
 *
 * @param ctx to alloc new string in. Should be a talloc pool a little bigger
 *	than the maximum serialized size of the entry.
 * @param out Where to write pointer to serialized cache entry.
 * @param c Cache entry to serialize.
 * @return 0 on success else -1.
 */
int cache_serialize(TALLOC_CTX *ctx, char **out, rlm_cache_entry_t *c)
{
	TALLOC_CTX *pairs = NULL;

	vp_cursor_t cursor;
	VALUE_PAIR *vp;

	char *to_store = NULL, *pair;

	to_store = talloc_asprintf(ctx, "&Cache-Expires = %" PRIu64 "\n&Cache-Created = %" PRIu64 "\n",
				   (uint64_t)c->expires, (uint64_t)c->created);
	if (!to_store) goto error;

	/*
	 *	It's valid to have an empty cache entry (save allocing the
	 *	pairs pool)
	 */
	if (!c->control && !c->packet && !c->reply) goto finish;

	/*
	 *  In the majority of cases using these pools reduces the number of mallocs
	 *  to two, except in the case where the total serialized pairs length is
	 *  greater than the pairs pool, or the total serialized string is greater
	 *  than the store pool.
	 */
	pairs = talloc_pool(ctx, 512);
	if (!pairs) {
	error:
		talloc_free(pairs);
		return -1;
	}

	if (c->control) {
		for (vp = fr_cursor_init(&cursor, &c->control);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			pair = vp_aprints(pairs, vp, '\'');
			if (!pair) goto error;

			to_store = talloc_asprintf_append_buffer(to_store, "&control:%s\n", pair);
			if (!to_store) goto error;
		}
	}

	if (c->packet) {
		for (vp = fr_cursor_init(&cursor, &c->packet);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			pair = vp_aprints(pairs, vp, '\'');
			if (!pair) goto error;

			to_store = talloc_asprintf_append_buffer(to_store, "&%s\n", pair);
			if (!to_store) goto error;
		}
	}

	if (c->reply) {
		for (vp = fr_cursor_init(&cursor, &c->reply);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			pair = vp_aprints(pairs, vp, '\'');
			if (!pair) goto error;

			to_store = talloc_asprintf_append_buffer(to_store, "&reply:%s\n", pair);
			if (!to_store) goto error;
		}
	}

finish:
	talloc_free(pairs);
	*out = to_store;

	return 0;
}
Beispiel #19
0
/*
  measure the speed of talloc versus malloc
*/
static bool test_speed(void)
{
	void *ctx = talloc_new(NULL);
	unsigned count;
	const int loop = 1000;
	int i;
	struct timeval tv;

	printf("test: speed\n# TALLOC VS MALLOC SPEED\n");

	tv = private_timeval_current();
	count = 0;
	do {
		void *p1, *p2, *p3;
		for (i=0;i<loop;i++) {
			p1 = talloc_size(ctx, loop % 100);
			p2 = talloc_strdup(p1, "foo bar");
			p3 = talloc_size(p1, 300);
			(void)p2;
			(void)p3;
			talloc_free(p1);
		}
		count += 3 * loop;
	} while (private_timeval_elapsed(&tv) < 5.0);

	fprintf(stderr, "talloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));

	talloc_free(ctx);

	ctx = talloc_pool(NULL, 1024);

	tv = private_timeval_current();
	count = 0;
	do {
		void *p1, *p2, *p3;
		for (i=0;i<loop;i++) {
			p1 = talloc_size(ctx, loop % 100);
			p2 = talloc_strdup(p1, "foo bar");
			p3 = talloc_size(p1, 300);
			(void)p2;
			(void)p3;
			talloc_free(p1);
		}
		count += 3 * loop;
	} while (private_timeval_elapsed(&tv) < 5.0);

	talloc_free(ctx);

	fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));

	tv = private_timeval_current();
	count = 0;
	do {
		void *p1, *p2, *p3;
		for (i=0;i<loop;i++) {
			p1 = malloc(loop % 100);
			p2 = strdup("foo bar");
			p3 = malloc(300);
			free(p1);
			free(p2);
			free(p3);
		}
		count += 3 * loop;
	} while (private_timeval_elapsed(&tv) < 5.0);
	fprintf(stderr, "malloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));

	printf("success: speed\n");

	return true;
}
/** Create and insert a cache entry.
 *
 * @return
 *	- #RLM_MODULE_OK on success.
 *	- #RLM_MODULE_UPDATED if we merged the cache entry.
 *	- #RLM_MODULE_FAIL on failure.
 */
static rlm_rcode_t cache_insert(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
				char const *key, int ttl)
{
	vp_map_t		const *map;
	vp_map_t		**last, *c_map;

	VALUE_PAIR		*vp;
	bool			merge = false;
	rlm_cache_entry_t	*c;

	TALLOC_CTX		*pool;

	if ((inst->max_entries > 0) && inst->module->count &&
	    (inst->module->count(inst, request, handle) > inst->max_entries)) {
		RWDEBUG("Cache is full: %d entries", inst->max_entries);
		return RLM_MODULE_FAIL;
	}

	c = cache_alloc(inst, request);
	if (!c) return RLM_MODULE_FAIL;

	c->key = talloc_typed_strdup(c, key);
	c->created = c->expires = request->timestamp;
	c->expires += ttl;

	last = &c->maps;

	RDEBUG("Creating new cache entry");

	/*
	 *	Alloc a pool so we don't have excessive mallocs when
	 *	gathering VALUE_PAIRs to cache.
	 */
	pool = talloc_pool(NULL, 1024);
	for (map = inst->maps; map != NULL; map = map->next) {
		VALUE_PAIR	*to_cache = NULL;
		vp_cursor_t	cursor;

		rad_assert(map->lhs && map->rhs);

		/*
		 *	Calling map_to_vp gives us exactly the same result,
		 *	as if this were an update section.
		 */
		if (map_to_vp(pool, &to_cache, request, map, NULL) < 0) {
			RDEBUG("Skipping %s", map->rhs->name);
			continue;
		}

		for (vp = fr_cursor_init(&cursor, &to_cache);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			/*
			 *	Prevent people from accidentally caching
			 *	cache control attributes.
			 */
			if (map->rhs->type == TMPL_TYPE_LIST) switch (vp->da->attr) {
			case PW_CACHE_TTL:
			case PW_CACHE_STATUS_ONLY:
			case PW_CACHE_READ_ONLY:
			case PW_CACHE_MERGE:
			case PW_CACHE_ENTRY_HITS:
				RDEBUG2("Skipping %s", vp->da->name);
				continue;

			default:
				break;
			}

			RINDENT();
			if (RDEBUG_ENABLED2) map_debug_log(request, map, vp);
			REXDENT();

			MEM(c_map = talloc_zero(c, vp_map_t));
			c_map->op = map->op;

			/*
			 *	Now we turn the VALUE_PAIRs into maps.
			 */
			switch (map->lhs->type) {
			/*
			 *	Attributes are easy, reuse the LHS, and create a new
			 *	RHS with the value_data_t from the VALUE_PAIR.
			 */
			case TMPL_TYPE_ATTR:
				c_map->lhs = map->lhs;	/* lhs shouldn't be touched, so this is ok */
			do_rhs:
				MEM(c_map->rhs = tmpl_init(talloc(c_map, vp_tmpl_t),
							   TMPL_TYPE_DATA, map->rhs->name, map->rhs->len));
				if (value_data_copy(c_map->rhs, &c_map->rhs->tmpl_data_value,
						    vp->da->type, &vp->data) < 0) {
					REDEBUG("Failed copying attribute value");
					talloc_free(pool);
					talloc_free(c);
					return RLM_MODULE_FAIL;
				}
				c_map->rhs->tmpl_data_type = vp->da->type;
				break;

			/*
			 *	Lists are weird... We need to fudge a new LHS template,
			 *	which is a combination of the LHS list and the attribute.
			 */
			case TMPL_TYPE_LIST:
			{
				char attr[256];

				MEM(c_map->lhs = tmpl_init(talloc(c_map, vp_tmpl_t),
							   TMPL_TYPE_ATTR, map->lhs->name, map->lhs->len));
				c_map->lhs->tmpl_da = vp->da;
				c_map->lhs->tmpl_tag = vp->tag;
				c_map->lhs->tmpl_list = map->lhs->tmpl_list;
				c_map->lhs->tmpl_num = map->lhs->tmpl_num;
				c_map->lhs->tmpl_request = map->lhs->tmpl_request;

				/*
				 *	We need to rebuild the attribute name, to be the
				 *	one we copied from the source list.
				 */
				c_map->lhs->len = tmpl_prints(attr, sizeof(attr), c_map->lhs, NULL);
				c_map->lhs->name = talloc_strdup(map->lhs, attr);
			}
				goto do_rhs;

			default:
				rad_assert(0);
			}
			*last = c_map;
			last = &(*last)->next;
		}
		talloc_free_children(pool); /* reset pool state */
	}
	talloc_free(pool);

	/*
	 *	Check to see if we need to merge the entry into the request
	 */
	vp = pairfind(request->config, PW_CACHE_MERGE, 0, TAG_ANY);
	if (vp && (vp->vp_integer > 0)) merge = true;

	if (merge) cache_merge(inst, request, c);

	for (;;) {
		cache_status_t ret;

		ret = inst->module->insert(inst, request, handle, c);
		switch (ret) {
		case CACHE_RECONNECT:
			if (cache_reconnect(inst, request, handle) == 0) continue;
			return RLM_MODULE_FAIL;

		case CACHE_OK:
			RDEBUG("Commited entry, TTL %d seconds", ttl);
			cache_free(inst, &c);
			return merge ? RLM_MODULE_UPDATED :
				       RLM_MODULE_OK;

		default:
			talloc_free(c);	/* Failed insertion - use talloc_free not the driver free */
			return RLM_MODULE_FAIL;
		}
	}
}