Ejemplo n.º 1
0
/* Load layer configurations from disk */
bool buxton_init_layers(void)
{
	bool ret = false;
	dictionary *ini;
	char *path;
	int nlayers = 0;

	path = DEFAULT_CONFIGURATION_FILE;

	ini = iniparser_load(path);
	if (ini == NULL) {
		buxton_log("Failed to load buxton conf file: %s\n", path);
		goto finish;
	}

	nlayers = iniparser_getnsec(ini);
	if (nlayers <= 0) {
		buxton_log("No layers defined in buxton conf file: %s\n", path);
		goto end;
	}

	_layers = hashmap_new(string_hash_func, string_compare_func);
	if (!_layers)
		goto end;

	for (int n = 0; n < nlayers; n++) {
		BuxtonLayer *layer;
		char *section_name;

		layer = malloc0(sizeof(BuxtonLayer));
		if (!layer)
			continue;

		section_name = iniparser_getsecname(ini, n);
		if (!section_name) {
			buxton_log("Failed to find section number: %d\n", n);
			continue;
		}

		if (!parse_layer(ini, section_name, layer)) {
			free(layer);
			buxton_log("Failed to load layer: %s\n", section_name);
			continue;
		}
		hashmap_put(_layers, layer->name, layer);
	}
	ret = true;

end:
	iniparser_freedict(ini);
finish:
	return ret;
}
Ejemplo n.º 2
0
static BuxtonLayer *buxton_layer_new(ConfigLayer *conf_layer)
{
	BuxtonLayer *out;

	assert(conf_layer);
	out= malloc0(sizeof(BuxtonLayer));
	if (!out) {
		abort();
	}

	if (conf_layer->priority < 0) {
		goto fail;
	}
	out->name.value = strdup(conf_layer->name);
	if (!out->name.value) {
		abort();
	}
	out->name.length = (uint32_t)strlen(conf_layer->name);

	if (strcmp(conf_layer->type, "System") == 0) {
		out->type = LAYER_SYSTEM;
	} else if (strcmp(conf_layer->type, "User") == 0) {
		out->type = LAYER_USER;
	} else {
		buxton_log("Layer %s has unknown type: %s\n", conf_layer->name, conf_layer->type);
		goto fail;
	}

	if (strcmp(conf_layer->backend, "gdbm") == 0) {
		out->backend = BACKEND_GDBM;
	} else if (strcmp(conf_layer->backend, "memory") == 0) {
		out->backend = BACKEND_MEMORY;
	} else {
		buxton_log("Layer %s has unknown database: %s\n", conf_layer->name, conf_layer->backend);
		goto fail;
	}

	if (conf_layer->description != NULL) {
		out->description = strdup(conf_layer->description);
		if (!out->description) {
			abort();
		}
	}

	out->priority = conf_layer->priority;
	return out;
fail:
	free(out->name.value);
	free(out->description);
	free(out);
	return NULL;
}
Ejemplo n.º 3
0
END_TEST

static Suite *
daemon_suite(void)
{
	Suite *s;
	TCase *tc;

	s = suite_create("smack");

	buxton_cache_smack_rules();
	if (buxton_smack_enabled()) {
		tc = tcase_create("smack access test functions");
		tcase_add_checked_fixture(tc, setup, teardown);
		/* TODO: add tests that use actual client Smack labels */
		suite_add_tcase(s, tc);

		tc = tcase_create("smack libsecurity functions");
		tcase_add_test(tc, smack_access_check);
		suite_add_tcase(s, tc);
	} else {
		buxton_log("Smack support not detected; skipping this test suite\n");
	}

	return s;
}
Ejemplo n.º 4
0
int buxton_watch_smack_rules(void)
{
	if (!have_smack) {
		errno = 0;
		return -1;
	}

	int fd;

	fd = inotify_init1(IN_NONBLOCK);
	if (fd < 0) {
		buxton_log("inotify_init(): %m\n");
		return -1;
	}
	if (inotify_add_watch(fd, buxton_smack_load_file(), IN_CLOSE_WRITE) < 0) {
		buxton_log("inotify_add_watch(): %m\n");
		return -1;
	}
	return fd;
}
Ejemplo n.º 5
0
int buxton_open(BuxtonClient *client)
{
	_BuxtonClient **c = (_BuxtonClient **)client;
	_BuxtonClient *cl = NULL;
	int bx_socket, r;
	struct sockaddr_un remote;
	size_t sock_name_len;

	if ((bx_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		return -1;
	}

	remote.sun_family = AF_UNIX;
	sock_name_len = strlen(buxton_socket()) + 1;
	if (sock_name_len >= sizeof(remote.sun_path)) {
		buxton_log("Provided socket name: %s is too long, maximum allowed length is %d bytes\n",
			   buxton_socket(), sizeof(remote.sun_path));
		return -1;
	}

	strncpy(remote.sun_path, buxton_socket(), sock_name_len);
	r = connect(bx_socket, (struct sockaddr *)&remote, sizeof(remote));
	if ( r == -1) {
		close(bx_socket);
		return -1;
	}

	if (fcntl(bx_socket, F_SETFL, O_NONBLOCK)) {
		close(bx_socket);
		return -1;
	}

	if (!setup_callbacks()) {
		close(bx_socket);
		return -1;
	}

	cl = malloc0(sizeof(_BuxtonClient));
	if (!cl) {
		close(bx_socket);
		return -1;
	}

	cl->fd = bx_socket;
	*c = cl;

	return bx_socket;
}
Ejemplo n.º 6
0
BuxtonBackend* backend_for_layer(BuxtonLayer *layer)
{
	BuxtonBackend *backend;

	assert(layer);

	if (!_databases)
		_databases = hashmap_new(string_hash_func, string_compare_func);
	if ((backend = (BuxtonBackend*)hashmap_get(_databases, layer->name)) == NULL) {
		/* attempt load of backend */
		backend = malloc0(sizeof(BuxtonBackend));
		if (!backend)
			return NULL;
		if (!init_backend(layer, backend)) {
			buxton_log("backend_for_layer(): failed to initialise backend for layer: %s\n", layer->name);
			free(backend);
			return NULL;
		}
		hashmap_put(_databases, layer->name, backend);
	}
	return (BuxtonBackend*)hashmap_get(_databases, layer->name);
}
Ejemplo n.º 7
0
bool buxton_cache_smack_rules(void)
{
	smack_check();

	FILE *load_file = NULL;
	char *rule_pair = NULL;
	int ret = true;
	bool have_rules = false;
	struct stat buf;

	if (_smackrules) {
		hashmap_free(_smackrules);
	}

	_smackrules = hashmap_new(string_hash_func, string_compare_func);

	if (!_smackrules) {
		abort();
	}

	//FIXME: should check for a proper mount point instead
	if ((stat(SMACK_MOUNT_DIR, &buf) == -1) || !S_ISDIR(buf.st_mode)) {
		buxton_log("Smack filesystem not detected; disabling Smack checks\n");
		have_smack = false;
		goto end;
	}

	load_file = fopen(buxton_smack_load_file(), "r");

	if (!load_file) {
		switch (errno) {
		case ENOENT:
			buxton_log("Smackfs load2 file not found; disabling Smack checks\n");
			have_smack = false;
			goto end;
		default:
			buxton_log("fopen(): %m\n");
			ret = false;
			goto end;
		}
	}

	do {
		int r;
		int chars;
		BuxtonKeyAccessType *accesstype;

		char subject[SMACK_LABEL_LEN+1] = { 0, };
		char object[SMACK_LABEL_LEN+1] = { 0, };
		char access[ACC_LEN] = { 0, };

		/* read contents from load2 */
		chars = fscanf(load_file, "%s %s %s\n", subject, object, access);

		if (ferror(load_file)) {
			buxton_log("fscanf(): %m\n");
			ret = false;
			goto end;
		}

		if (!have_rules && chars == EOF && feof(load_file)) {
			buxton_debug("No loaded Smack rules found\n");
			goto end;
		}

		if (chars != 3) {
			buxton_log("Corrupt load file detected\n");
			ret = false;
			goto end;
		}

		have_rules = true;

		r = asprintf(&rule_pair, "%s %s", subject, object);
		if (r == -1) {
			abort();
		}

		accesstype = malloc0(sizeof(BuxtonKeyAccessType));
		if (!accesstype) {
			abort();
		}

		*accesstype = ACCESS_NONE;

		if (strchr(access, 'r')) {
			*accesstype |= ACCESS_READ;
		}

		if (strchr(access, 'w')) {
			*accesstype |= ACCESS_WRITE;
		}

		hashmap_put(_smackrules, rule_pair, accesstype);

	} while (!feof(load_file));

end:
	if (load_file) {
		fclose(load_file);
	}

	return ret;
}
Ejemplo n.º 8
0
bool parse_layer(dictionary *ini, char *name, BuxtonLayer *out)
{
	bool ret = false;
	int r;
	char *k_desc = NULL;
	char *k_backend = NULL;
	char *k_type = NULL;
	char *k_priority = NULL;
	char *_desc = NULL;
	char *_backend = NULL;
	char *_type = NULL;
	char *_priority = NULL;

	assert(ini);
	assert(name);
	assert(out);

	r = asprintf(&k_desc, "%s:description", name);
	if (r == -1)
		goto end;

	r = asprintf(&k_backend, "%s:backend", name);
	if (r == -1)
		goto end;

	r = asprintf(&k_type, "%s:type", name);
	if (r == -1)
		goto end;

	r = asprintf(&k_priority, "%s:priority", name);
	if (r == -1)
		goto end;

	_type = iniparser_getstring(ini, k_type, NULL);
	_backend = iniparser_getstring(ini, k_backend, NULL);
	_priority = iniparser_getstring(ini, k_priority, NULL);
	_desc = iniparser_getstring(ini, k_desc, NULL);

	if (!_type || !name || !_backend || !_priority)
		goto end;

	out->name = strdup(name);
	if (!out->name)
		goto fail;

	if (strcmp(_type, "System") == 0)
		out->type = LAYER_SYSTEM;
	else if (strcmp(_type, "User") == 0)
		out->type = LAYER_USER;
	else {
		buxton_log("Layer %s has unknown type: %s\n", name, _type);
		goto fail;
	}

	if (strcmp(_backend, "gdbm") == 0)
		out->backend = BACKEND_GDBM;
	else if(strcmp(_backend, "memory") == 0)
		out->backend = BACKEND_MEMORY;
	else
		goto fail;

	out->priority = strdup(_backend);
	if (!out->priority)
		goto fail;

	if (_desc != NULL)
		out->description = strdup(_desc);

	ret = true;
	goto end;

fail:
	if (out->name)
		free(out->name);
	if (out->description)
		free(out->description);
	if (out->priority)
		free(out->priority);

end:
	if (k_desc)
		free(k_desc);
	if (k_backend)
		free(k_backend);
	if (k_type)
		free(k_type);
	if (k_priority)
		free(k_priority);

	return ret;
}
Ejemplo n.º 9
0
bool init_backend(BuxtonLayer *layer, BuxtonBackend* backend)
{
	void *handle, *cast;
	char *path;
	const char *name;
	char *error;
	int r;
	module_init_func i_func;
	module_destroy_func d_func;

	assert(layer);
	assert(backend);

	if (layer->backend == BACKEND_GDBM)
		name = "gdbm";
	else if (layer->backend == BACKEND_MEMORY)
		name = "memory";
	else
		return false;

	r = asprintf(&path, "%s/%s.so", MODULE_DIRECTORY, name);
	if (r == -1)
		return false;

	/* Load the module */
	handle = dlopen(path, RTLD_LAZY);
	free(path);

	if (!handle) {
		buxton_log("dlopen(): %s\n", dlerror());
		return false;
	}

	dlerror();
	cast = dlsym(handle, "buxton_module_init");
	if ((error = dlerror()) != NULL || !cast) {
		buxton_log("dlsym(): %s", error);
		dlclose(handle);
		return false;
	}
	memcpy(&i_func, &cast, sizeof(i_func));
	dlerror();

	cast = dlsym(handle, "buxton_module_destroy");
	if ((error = dlerror()) != NULL || !cast) {
		buxton_log("dlsym(): %s", error);
		dlclose(handle);
		return false;
	}
	memcpy(&d_func, &cast, sizeof(d_func));

	i_func(backend);
	if (backend == NULL) {
		buxton_log("buxton_module_init returned NULL");
		dlclose(handle);
		return false;
	}
	backend->module = handle;
	backend->destroy = d_func;

	return true;
}
Ejemplo n.º 10
0
/**
 * Entry point into bt-daemon
 * @param argc Number of arguments passed
 * @param argv An array of string arguments
 * @returns EXIT_SUCCESS if the operation succeeded, otherwise EXIT_FAILURE
 */
int main(int argc, char *argv[])
{
	int fd;
	int smackfd = -1;
	socklen_t addr_len;
	struct sockaddr_un remote;
	int descriptors;
	int ret;
	bool manual_start = false;
	struct sigaction sa;

	if (!buxton_cache_smack_rules())
		exit(EXIT_FAILURE);
	smackfd = buxton_watch_smack_rules();
	if (smackfd < 0 && errno)
		exit(EXIT_FAILURE);

	self.nfds_alloc = 0;
	self.accepting_alloc = 0;
	self.nfds = 0;
	self.buxton.client.direct = true;
	self.buxton.client.uid = geteuid();
	if (!buxton_direct_open(&self.buxton))
		exit(EXIT_FAILURE);

	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	sa.sa_handler = my_handler;
	ret = sigaction(SIGINT, &sa, NULL);
	if (ret == -1)
		exit(EXIT_FAILURE);
	ret = sigaction(SIGTERM, &sa, NULL);
	if (ret == -1)
		exit(EXIT_FAILURE);

	/* For client notifications */
	self.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
	/* Store a list of connected clients */
	LIST_HEAD_INIT(client_list_item, self.client_list);

	descriptors = sd_listen_fds(0);
	if (descriptors < 0) {
		buxton_log("sd_listen_fds: %m\n");
		exit(EXIT_FAILURE);
	} else if (descriptors == 0) {
		/* Manual invocation */
		manual_start = true;
		union {
			struct sockaddr sa;
			struct sockaddr_un un;
		} sa;

		fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if (fd < 0) {
			buxton_log("socket(): %m\n");
			exit(EXIT_FAILURE);
		}

		memset(&sa, 0, sizeof(sa));
		sa.un.sun_family = AF_UNIX;
		strncpy(sa.un.sun_path, BUXTON_SOCKET, sizeof(sa.un.sun_path) - 1);
		sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;

		ret = unlink(sa.un.sun_path);
		if (ret == -1 && errno != ENOENT) {
			exit(EXIT_FAILURE);
		}

		if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
			buxton_log("bind(): %m\n");
			exit(EXIT_FAILURE);
		}

		chmod(sa.un.sun_path, 0666);

		if (listen(fd, SOMAXCONN) < 0) {
			buxton_log("listen(): %m\n");
			exit(EXIT_FAILURE);
		}
		add_pollfd(&self, fd, POLLIN | POLLPRI, true);
	} else {
		/* systemd socket activation */
		for (fd = SD_LISTEN_FDS_START + 0; fd < SD_LISTEN_FDS_START + descriptors; fd++) {
			if (sd_is_fifo(fd, NULL)) {
				add_pollfd(&self, fd, POLLIN, false);
				buxton_debug("Added fd %d type FIFO\n", fd);
			} else if (sd_is_socket_unix(fd, SOCK_STREAM, -1, BUXTON_SOCKET, 0)) {
				add_pollfd(&self, fd, POLLIN | POLLPRI, true);
				buxton_debug("Added fd %d type UNIX\n", fd);
			} else if (sd_is_socket(fd, AF_UNSPEC, 0, -1)) {
				add_pollfd(&self, fd, POLLIN | POLLPRI, true);
				buxton_debug("Added fd %d type SOCKET\n", fd);
			}
		}
	}

	if (smackfd >= 0) {
		/* add Smack rule fd to pollfds */
		add_pollfd(&self, smackfd, POLLIN | POLLPRI, false);
	}

	buxton_log("%s: Started\n", argv[0]);

	/* Enter loop to accept clients */
	for (;;) {
		ret = poll(self.pollfds, self.nfds, -1);

		if (ret < 0) {
			buxton_log("poll(): %m\n");
			if (errno == EINTR) {
				if (do_shutdown)
					break;
				else
					continue;
			}
			break;
		}
		if (ret == 0)
			continue;

		for (nfds_t i=0; i<self.nfds; i++) {
			client_list_item *cl = NULL;
			char discard[256];

			if (self.pollfds[i].revents == 0)
				continue;

			if (self.pollfds[i].fd == -1) {
				/* TODO: Remove client from list  */
				buxton_debug("Removing / Closing client for fd %d\n", self.pollfds[i].fd);
				del_pollfd(&self, i);
				continue;
			}

			if (smackfd >= 0) {
				if (self.pollfds[i].fd == smackfd) {
					if (!buxton_cache_smack_rules())
						exit(EXIT_FAILURE);
					buxton_log("Reloaded Smack access rules\n");
					/* discard inotify data itself */
					while (read(smackfd, &discard, 256) == 256);
					continue;
				}
			}

			if (self.accepting[i] == true) {
				struct timeval tv;
				int fd;
				int on = 1;

				addr_len = sizeof(remote);

				if ((fd = accept(self.pollfds[i].fd,
				    (struct sockaddr *)&remote, &addr_len)) == -1) {
					buxton_log("accept(): %m\n");
					break;
				}

				buxton_debug("New client fd %d connected through fd %d\n", fd, self.pollfds[i].fd);

				cl = malloc0(sizeof(client_list_item));
				if (!cl)
					exit(EXIT_FAILURE);

				LIST_INIT(client_list_item, item, cl);

				cl->fd = fd;
				cl->cred = (struct ucred) {0, 0, 0};
				LIST_PREPEND(client_list_item, item, self.client_list, cl);

				/* poll for data on this new client as well */
				add_pollfd(&self, cl->fd, POLLIN | POLLPRI, false);

				/* Mark our packets as high prio */
				if (setsockopt(cl->fd, SOL_SOCKET, SO_PRIORITY, &on, sizeof(on)) == -1)
					buxton_log("setsockopt(SO_PRIORITY): %m\n");

				/* Set socket recv timeout */
				tv.tv_sec = SOCKET_TIMEOUT;
				tv.tv_usec = 0;
				if (setsockopt(cl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
					       sizeof(struct timeval)) == -1)
					buxton_log("setsockopt(SO_RCVTIMEO): %m\n");

				/* check if this is optimal or not */
				break;
			}

			assert(self.accepting[i] == 0);
			if (smackfd >= 0)
				assert(self.pollfds[i].fd != smackfd);

			/* handle data on any connection */
			/* TODO: Replace with hash table lookup */
			LIST_FOREACH(item, cl, self.client_list)
				if (self.pollfds[i].fd == cl->fd)
					break;

			assert(cl);
			handle_client(&self, cl, i);
		}
	}

	buxton_log("%s: Closing all connections\n", argv[0]);

	if (manual_start)
		unlink(BUXTON_SOCKET);
	for (int i = 0; i < self.nfds; i++) {
		close(self.pollfds[i].fd);
	}
	for (client_list_item *i = self.client_list; i;) {
		client_list_item *j = i->item_next;
		free(i);
		i = j;
	}
	hashmap_free(self.notify_mapping);
	buxton_direct_close(&self.buxton);
	return EXIT_SUCCESS;
}
Ejemplo n.º 11
0
static void init_backend(BuxtonConfig *config,
			 BuxtonLayer *layer,
			 BuxtonBackend **backend)
{
	void *handle, *cast;
	_cleanup_free_ char *path = NULL;
	const char *name;
	char *error;
	int r;
	bool rb;
	module_init_func i_func;
	module_destroy_func d_func;
	BuxtonBackend *backend_tmp;

	assert(layer);
	assert(backend);

	if (layer->backend == BACKEND_GDBM) {
		name = "gdbm";
	} else if (layer->backend == BACKEND_MEMORY) {
		name = "memory";
	} else {
		buxton_log("Invalid backend type for layer: %s\n", layer->name);
		abort();
	}

	backend_tmp = hashmap_get(config->backends, name);

	if (backend_tmp) {
		*backend = backend_tmp;
		return;
	}

	backend_tmp = malloc0(sizeof(BuxtonBackend));
	if (!backend_tmp) {
		abort();
	}

	r = asprintf(&path, "%s/%s.so", buxton_module_dir(), name);
	if (r == -1) {
		abort();
	}

	/* Load the module */
	handle = dlopen(path, RTLD_LAZY);

	if (!handle) {
		buxton_log("dlopen(): %s\n", dlerror());
		abort();
	}

	dlerror();
	cast = dlsym(handle, "buxton_module_init");
	if ((error = dlerror()) != NULL || !cast) {
		buxton_log("dlsym(): %s\n", error);
		abort();
	}
	memcpy(&i_func, &cast, sizeof(i_func));
	dlerror();

	cast = dlsym(handle, "buxton_module_destroy");
	if ((error = dlerror()) != NULL || !cast) {
		buxton_log("dlsym(): %s\n", error);
		abort();
	}
	memcpy(&d_func, &cast, sizeof(d_func));

	rb = i_func(backend_tmp);
	if (!rb) {
		buxton_log("buxton_module_init failed\n");
		abort();
	}

	if (!config->backends) {
		config->backends = hashmap_new(trivial_hash_func, trivial_compare_func);
		if (!config->backends) {
			abort();
		}
	}

	r = hashmap_put(config->backends, name, backend_tmp);
	if (r != 1) {
		abort();
	}

	backend_tmp->module = handle;
	backend_tmp->destroy = d_func;

	*backend = backend_tmp;
}
Ejemplo n.º 12
0
size_t buxton_serialize_message(uint8_t **dest, BuxtonControlMessage message,
				uint32_t msgid, BuxtonArray *list)
{
	uint16_t i = 0;
	uint8_t *data = NULL;
	size_t ret = 0;
	size_t offset = 0;
	size_t size = 0;
	size_t curSize = 0;
	uint16_t control, msg;

	assert(dest);
	assert(list);

	buxton_debug("Serializing message...\n");

	if (list->len > BUXTON_MESSAGE_MAX_PARAMS) {
		errno = EINVAL;
		return ret;
	}

	if (message >= BUXTON_CONTROL_MAX || message < BUXTON_CONTROL_SET) {
		errno = EINVAL;
		return ret;
	}

	/*
	 * initial size =
	 * control code + control message (uint16_t * 2) +
	 * message size (uint32_t) +
	 * message id (uint32_t) +
	 * param count (uint32_t)
	 */
	data = malloc0(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) +
		       sizeof(uint32_t));
	if (!data) {
		errno = ENOMEM;
		goto end;
	}

	control = BUXTON_CONTROL_CODE;
	memcpy(data, &control, sizeof(uint16_t));
	offset += sizeof(uint16_t);

	msg = (uint16_t)message;
	memcpy(data+offset, &msg, sizeof(uint16_t));
	offset += sizeof(uint16_t);

	/* Save room for final size */
	offset += sizeof(uint32_t);

	memcpy(data+offset, &msgid, sizeof(uint32_t));
	offset += sizeof(uint32_t);

	/* Now write the parameter count */
	memcpy(data+offset, &(list->len), sizeof(uint32_t));
	offset += sizeof(uint32_t);

	size = offset;

	/* Deal with parameters */
	BuxtonData *param;
	size_t p_length = 0;
	for (i=0; i < list->len; i++) {
		param = buxton_array_get(list, i);
		if (!param) {
			errno = EINVAL;
			goto fail;
		}

		switch (param->type) {
		case BUXTON_TYPE_STRING:
			p_length = param->store.d_string.length;
			break;
		case BUXTON_TYPE_INT32:
			p_length = sizeof(int32_t);
			break;
		case BUXTON_TYPE_UINT32:
			p_length = sizeof(uint32_t);
			break;
		case BUXTON_TYPE_INT64:
			p_length = sizeof(int64_t);
			break;
		case BUXTON_TYPE_UINT64:
			p_length = sizeof(uint64_t);
			break;
		case BUXTON_TYPE_FLOAT:
			p_length = sizeof(float);
			break;
		case BUXTON_TYPE_DOUBLE:
			p_length = sizeof(double);
			break;
		case BUXTON_TYPE_BOOLEAN:
			p_length = sizeof(bool);
			break;
		default:
			errno = EINVAL;
			buxton_log("Invalid parameter type %lu\n", param->type);
			goto fail;
		};

		buxton_debug("offset: %lu\n", offset);
		buxton_debug("value length: %lu\n", p_length);

		/* Need to allocate enough room to hold this data */
		size += sizeof(uint16_t) + sizeof(uint32_t) + p_length;

		if (curSize < size) {
			if (!(data = greedy_realloc((void**)&data, &curSize, size))) {
				errno = ENOMEM;
				goto fail;
			}
			memzero(data+offset, size - offset);
		}

		/* Copy data type */
		memcpy(data+offset, &(param->type), sizeof(uint16_t));
		offset += sizeof(uint16_t);

		/* Write out the length of value */
		memcpy(data+offset, &p_length, sizeof(uint32_t));
		offset += sizeof(uint32_t);

		switch (param->type) {
		case BUXTON_TYPE_STRING:
			memcpy(data+offset, param->store.d_string.value, p_length);
			break;
		case BUXTON_TYPE_INT32:
			memcpy(data+offset, &(param->store.d_int32), sizeof(int32_t));
			break;
		case BUXTON_TYPE_UINT32:
			memcpy(data+offset, &(param->store.d_uint32), sizeof(uint32_t));
			break;
		case BUXTON_TYPE_INT64:
			memcpy(data+offset, &(param->store.d_int64), sizeof(int64_t));
			break;
		case BUXTON_TYPE_UINT64:
			memcpy(data+offset, &(param->store.d_uint64), sizeof(uint64_t));
			break;
		case BUXTON_TYPE_FLOAT:
			memcpy(data+offset, &(param->store.d_float), sizeof(float));
			break;
		case BUXTON_TYPE_DOUBLE:
			memcpy(data+offset, &(param->store.d_double), sizeof(double));
			break;
		case BUXTON_TYPE_BOOLEAN:
			memcpy(data+offset, &(param->store.d_boolean), sizeof(bool));
			break;
		default:
			/* already tested this above, can't get here
			 * normally */
			assert(0);
		};
		offset += p_length;
		p_length = 0;
	}

	memcpy(data+BUXTON_LENGTH_OFFSET, &offset, sizeof(uint32_t));

	ret = offset;
	*dest = data;

fail:
	/* Clean up */
	if (ret == 0) {
		free(data);
	}
end:
	buxton_debug("Serializing returned:%lu\n", ret);
	return ret;
}