Example #1
0
mowgli_linebuf_t *
mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata)
{
	mowgli_linebuf_t *linebuf;

	if (linebuf_heap == NULL)
		linebuf_heap = mowgli_heap_create(sizeof(mowgli_linebuf_t), 16, BH_NOW);

	linebuf = mowgli_heap_alloc(linebuf_heap);

	/* Sane default */
	mowgli_linebuf_delim(linebuf, "\r\n", "\r\n");
	linebuf->readline_cb = cb;

	linebuf->flags = 0;

	linebuf->readbuf.buffer = NULL;
	linebuf->writebuf.buffer = NULL;
	mowgli_linebuf_setbuflen(&(linebuf->readbuf), 65536);
	mowgli_linebuf_setbuflen(&(linebuf->writebuf), 65536);

	linebuf->eventloop = NULL;

	linebuf->return_normal_strings = true;	/* This is generally what you want, but beware of malicious \0's in input data! */

	linebuf->userdata = userdata;

	linebuf->vio = mowgli_vio_create(linebuf);

	return linebuf;
}
Example #2
0
int
mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops)
{
	mowgli_ssl_connection_t *connection;

	return_val_if_fail(vio, -255);

	if (!ssl_heap)
		ssl_heap = mowgli_heap_create(sizeof(mowgli_ssl_connection_t), 64, BH_NOW);

	connection = mowgli_heap_alloc(ssl_heap);
	vio->privdata = connection;

	if (settings)
		memcpy(&connection->settings, settings, sizeof(mowgli_vio_ssl_settings_t));
	else
		/* Greatest compat without being terribly insecure */
		connection->settings.ssl_version = MOWGLI_VIO_SSLFLAGS_SSLV3;

	if (ops == NULL)
	{
		if (!openssl_ops)
		{
			openssl_ops = mowgli_alloc(sizeof(mowgli_vio_ops_t));
			memcpy(openssl_ops, &mowgli_vio_default_ops, sizeof(mowgli_vio_ops_t));
		}

		vio->ops = openssl_ops;
	}
	else
	{
		vio->ops = ops;
	}

	/* Change ops */
	mowgli_vio_ops_set_op(vio->ops, connect, mowgli_vio_openssl_default_connect);
	mowgli_vio_ops_set_op(vio->ops, read, mowgli_vio_openssl_default_read);
	mowgli_vio_ops_set_op(vio->ops, write, mowgli_vio_openssl_default_write);
	mowgli_vio_ops_set_op(vio->ops, close, mowgli_vio_openssl_default_close);
	mowgli_vio_ops_set_op(vio->ops, accept, mowgli_vio_openssl_default_accept);
	mowgli_vio_ops_set_op(vio->ops, listen, mowgli_vio_openssl_default_listen);

	/* SSL setup */
	if (!openssl_init)
	{
		openssl_init = true;
		SSL_library_init();
		SSL_load_error_strings();
		ERR_load_BIO_strings();
		OpenSSL_add_all_algorithms();
	}

	return 0;
}
Example #3
0
static struct myentity *
chanacs_validate_f(const char *param)
{
	static const struct entity_chanacs_validation_vtable chanacs_ext_validate = {
		.match_entity = chanacs_ext_match_entity,
		.match_user = chanacs_ext_match_user,
		.can_register_channel = chanacs_ext_can_register_channel,
		.allow_foundership = chanacs_allow_foundership,
	};

	char *name;
	struct this_exttarget *ext;
	size_t namelen;

	if (param == NULL)
		return NULL;

	if (*param == '\0')
		return NULL;

	// if we already have an object, return it from our tree.
	if ((ext = mowgli_patricia_retrieve(chanacs_exttarget_tree, param)) != NULL)
		return entity(ext);

	ext = mowgli_heap_alloc(chanacs_ext_heap);
	ext->channel = strshare_get(param);
	ext->checking = 0;

	// name the entity... $chanacs:param
#define NAMEPREFIX "$chanacs:"
	namelen = sizeof NAMEPREFIX + strlen(param);

	name = smalloc(namelen);
	memcpy(name, NAMEPREFIX, sizeof NAMEPREFIX - 1);
	memcpy(name + sizeof NAMEPREFIX - 1, param, namelen - sizeof NAMEPREFIX + 1);

	entity(ext)->name = strshare_get(name);
	sfree(name);
#undef NAMEPREFIX

	// hook up the entity's validation table.
	entity(ext)->chanacs_validate = &chanacs_ext_validate;
	entity(ext)->type = ENT_EXTTARGET;

	// initialize the object.
	atheme_object_init(atheme_object(ext), entity(ext)->name, (atheme_object_destructor_fn) chanacs_ext_delete);

	// add the object to the exttarget tree
	mowgli_patricia_add(chanacs_exttarget_tree, ext->channel, ext);

	// return the object as initially unowned by sinking the reference count.
	return atheme_object_sink_ref(ext);
}
Example #4
0
mowgli_queue_t *
mowgli_queue_push(mowgli_queue_t *head, void *data)
{
	mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap);

	return_val_if_fail(head != NULL, NULL);

	out->prev = head;
	out->data = data;

	if (head != NULL)
		head->next = out;

	return out;
}
Example #5
0
mowgli_eventloop_t *
mowgli_eventloop_create(void)
{
	mowgli_eventloop_t *eventloop;

	if (eventloop_heap == NULL)
		eventloop_heap = mowgli_heap_create(sizeof(mowgli_eventloop_t), 16, BH_NOW);

	eventloop = mowgli_heap_alloc(eventloop_heap);

	eventloop->eventloop_ops = &_mowgli_null_pollops;

#ifdef HAVE_SELECT
	eventloop->eventloop_ops = &_mowgli_select_pollops;
#endif
#ifdef HAVE_POLL_H
	eventloop->eventloop_ops = &_mowgli_poll_pollops;
#endif
#ifdef HAVE_SYS_EPOLL_H
	eventloop->eventloop_ops = &_mowgli_epoll_pollops;
#endif
#ifdef HAVE_KQUEUE
	eventloop->eventloop_ops = &_mowgli_kqueue_pollops;
#endif
#ifdef HAVE_DISPATCH_BLOCK
	eventloop->eventloop_ops = &_mowgli_qnx_pollops;
#endif
#ifdef HAVE_PORT_CREATE
	eventloop->eventloop_ops = &_mowgli_ports_pollops;
#endif
#if 0
	eventloop->eventloop_ops = &_mowgli_winsock_pollops;
#endif

	if (mowgli_mutex_init(&eventloop->mutex) != 0)
	{
		mowgli_log("couldn't create mutex for eventloop %p, aborting...", (void *) eventloop);
		abort();
	}

	eventloop->eventloop_ops->pollsetup(eventloop);

	eventloop->deadline = -1;

	mowgli_eventloop_calibrate(eventloop);

	return eventloop;
}
Example #6
0
static myentity_t *chanacs_validate_f(const char *param)
{
	char *name;
	chanacs_exttarget_t *ext;
	size_t namelen;

	if (param == NULL)
		return NULL;

	if (*param == '\0')
		return NULL;

	/* if we already have an object, return it from our tree. */
	if ((ext = mowgli_patricia_retrieve(chanacs_exttarget_tree, param)) != NULL)
		return entity(ext);

	ext = mowgli_heap_alloc(chanacs_ext_heap);
	ext->channel = strshare_get(param);
	ext->checking = 0;

	/* name the entity... $chanacs:param */
#define NAMEPREFIX "$chanacs:"
	namelen = sizeof NAMEPREFIX + strlen(param);

	name = smalloc(namelen);
	memcpy(name, NAMEPREFIX, sizeof NAMEPREFIX - 1);
	memcpy(name + sizeof NAMEPREFIX - 1, param, namelen - sizeof NAMEPREFIX + 1);

	entity(ext)->name = strshare_get(name);
	free(name);
#undef NAMEPREFIX

	/* hook up the entity's validation table. */
	entity(ext)->chanacs_validate = &chanacs_ext_validate;
	entity(ext)->type = ENT_EXTTARGET;

	/* initialize the object. */
	object_init(object(ext), entity(ext)->name, (destructor_t) chanacs_ext_delete);

	/* add the object to the exttarget tree */
	mowgli_patricia_add(chanacs_exttarget_tree, ext->channel, ext);

	/* return the object as initially unowned by sinking the reference count. */
	return object_sink_ref(ext);
}
Example #7
0
void pcommand_add(const char *token, void (*handler) (sourceinfo_t *si, int parc, char *parv[]), int minparc, int sourcetype)
{
	pcommand_t *pcmd;

	if (pcommand_find(token))
	{
		slog(LG_INFO, "pcommand_add(): token %s is already registered", token);
		return;
	}

	pcmd = mowgli_heap_alloc(pcommand_heap);
	pcmd->token = sstrdup(token);
	pcmd->handler = handler;
	pcmd->minparc = minparc;
	pcmd->sourcetype = sourcetype;

	mowgli_patricia_add(pcommands, pcmd->token, pcmd);
}
Example #8
0
mowgli_queue_t *
mowgli_queue_shift(mowgli_queue_t *head, void *data)
{
	mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap);

	return_val_if_fail(head != NULL, NULL);

	out->next = head;
	out->data = data;

	if (head != NULL)
	{
		out->prev = head->prev;

		if (out->prev != NULL)
			out->prev->next = out;

		head->prev = out;
	}

	return out;
}
static void os_cmd_resolve(sourceinfo_t *si, int parc, char *parv[])
{
	resolve_req_t *req;

	if (request_heap == NULL)
		request_heap = mowgli_heap_create(sizeof(resolve_req_t), 32, BH_LAZY);

	if (!parv[0])
	{
		command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "RESOLVE");
		return;
	}

	req = mowgli_heap_alloc(request_heap);

	req->si = si;
	req->dns_query.ptr = req;
	req->dns_query.callback = resolve_cb;

	gethost_byname_type(parv[0], &req->dns_query, T_A);

	object_ref(req->si);
}
Example #10
0
/*
 * server_add(const char *name, unsigned int hops, const char *uplink,
 *            const char *id, const char *desc)
 *
 * Server object factory.
 *
 * Inputs:
 *     - name of server object to create or NULL if it's a masked server
 *     - amount of hops server has from services
 *     - name of server's uplink or NULL if it's us
 *     - SID of uplink if applicable otherwise NULL
 *     - server's description
 *
 * Outputs:
 *     - on success, a new server object
 *
 * Side Effects:
 *     - the new server object is added to the server and sid DTree.
 */
server_t *server_add(const char *name, unsigned int hops, server_t *uplink, const char *id, const char *desc)
{
	server_t *s;
	const char *tld;

	/* Masked servers must have a SID */
	return_val_if_fail(name != NULL || id != NULL, NULL);
	/* Masked servers must be behind something else */
	return_val_if_fail(name != NULL || uplink != NULL, NULL);

	if (uplink)
	{
		if (name == NULL)
			slog(LG_NETWORK, "server_add(): %s (%s), masked", uplink->name, id);
		else if (id != NULL)
			slog(LG_NETWORK, "server_add(): %s (%s), uplink %s", name, id, uplink->name);
		else
			slog(LG_NETWORK, "server_add(): %s, uplink %s", name, uplink->name);
	}
	else
		slog(LG_DEBUG, "server_add(): %s, root", name);

	s = mowgli_heap_alloc(serv_heap);

	if (id != NULL)
	{
		s->sid = sstrdup(id);
		mowgli_patricia_add(sidlist, s->sid, s);
	}

	/* check to see if it's hidden */
	if (!strncmp(desc, "(H)", 3))
	{
		s->flags |= SF_HIDE;
		desc += 3;
		if (*desc == ' ')
			desc++;
	}

	s->name = sstrdup(name != NULL ? name : uplink->name);
	s->desc = sstrdup(desc);
	s->hops = hops;
	s->connected_since = CURRTIME;

	if (name != NULL)
		mowgli_patricia_add(servlist, s->name, s);
	else
		s->flags |= SF_MASKED;

	if (uplink)
	{
		s->uplink = uplink;
		mowgli_node_add(s, mowgli_node_create(), &uplink->children);
	}

	/* tld list for global noticer */
	tld = strrchr(s->name, '.');

	if (tld != NULL)
	{
		if (!tld_find(tld))
			tld_add(tld);
	}

	cnt.server++;

	hook_call_server_add(s);

	return s;
}
Example #11
0
/*
 * user_add(const char *nick, const char *user, const char *host, const char *vhost, const char *ip,
 *          const char *uid, const char *gecos, server_t *server, time_t ts);
 *
 * User object factory.
 *
 * Inputs:
 *     - nickname of new user
 *     - username of new user
 *     - hostname of new user
 *     - virtual hostname of new user if applicable otherwise NULL
 *     - ip of user if applicable otherwise NULL
 *     - unique identifier (UID) of user if appliable otherwise NULL
 *     - gecos of new user
 *     - pointer to server new user is on
 *     - user's timestamp
 *
 * Outputs:
 *     - on success, a new user
 *     - on failure, NULL
 *
 * Side Effects:
 *     - if successful, a user is created and added to the users DTree.
 *     - if unsuccessful, a kill has been sent if necessary
 */
user_t *user_add(const char *nick, const char *user, const char *host,
	const char *vhost, const char *ip, const char *uid, const char *gecos,
	server_t *server, time_t ts)
{
	user_t *u, *u2;
	hook_user_nick_t hdata;

	slog(LG_DEBUG, "user_add(): %s (%s@%s) -> %s", nick, user, host, server->name);

	u2 = user_find_named(nick);
	if (u2 != NULL)
	{
		if (server == me.me)
		{
			/* caller should not let this happen */
			slog(LG_ERROR, "user_add(): tried to add local nick %s which already exists", nick);
			return NULL;
		}
		slog(LG_INFO, "user_add(): nick collision on %s", nick);
		if (u2->server == me.me)
		{
			if (uid != NULL)
			{
				/* If the new client has a UID, our
				 * client will have a UID too and the
				 * remote server will send us a kill
				 * if it kills our client.  So just kill
				 * their client and continue.
				 */
				kill_id_sts(NULL, uid, "Nick collision with services (new)");
				return NULL;
			}
			if (ts == u2->ts || ((ts < u2->ts) ^ (!irccasecmp(user, u2->user) && !irccasecmp(host, u2->host))))
			{
				/* If the TSes are equal, or if their TS
				 * is less than our TS and the u@h differs,
				 * or if our TS is less than their TS and
				 * the u@h is equal, our client will be
				 * killed.
				 *
				 * Hope that a kill has arrived just before
				 * for our client; we will have reintroduced
				 * it.
				 */
				return NULL;
			}
			else /* Our client will not be killed. */
				return NULL;
		}
		else
		{
			wallops("Server %s is introducing nick %s which already exists on %s",
					server->name, nick, u2->server->name);
			if (uid != NULL && u2->uid != NULL)
			{
				kill_id_sts(NULL, uid, "Ghost detected via nick collision (new)");
				kill_id_sts(NULL, u2->uid, "Ghost detected via nick collision (old)");
				user_delete(u2, "Ghost detected via nick collision (old)");
			}
			else
			{
				/* There is no way we can do this properly. */
				kill_id_sts(NULL, nick, "Ghost detected via nick collision");
				user_delete(u2, "Ghost detected via nick collision");
			}
			return NULL;
		}
	}

	u = mowgli_heap_alloc(user_heap);
	object_init(object(u), nick, (destructor_t) user_delete);

	if (uid != NULL)
	{
		u->uid = strshare_get(uid);
		mowgli_patricia_add(uidlist, u->uid, u);
	}

	u->nick = strshare_get(nick);
	u->user = strshare_get(user);
	u->host = strshare_get(host);
	u->gecos = strshare_get(gecos);
	u->chost = strshare_get(vhost ? vhost : host);
	u->vhost = strshare_get(vhost ? vhost : host);

	if (ip && strcmp(ip, "0") && strcmp(ip, "0.0.0.0") && strcmp(ip, "255.255.255.255"))
		u->ip = strshare_get(ip);

	u->server = server;
	u->server->users++;
	mowgli_node_add(u, &u->snode, &u->server->userlist);

	u->ts = ts ? ts : CURRTIME;

	mowgli_patricia_add(userlist, u->nick, u);

	cnt.user++;

	hdata.u = u;
	hdata.oldnick = NULL;
	hook_call_user_add(&hdata);

	return hdata.u;
}
Example #12
0
/*
 * Implementation functions: load or unload a perl script.
 */
static module_t *do_script_load(const char *filename)
{
	/* Remember, this must now be re-entrant. The use of the static
	 * perl_error buffer is still OK, as it's only used immediately after
	 * setting, without control passing from this function.
	 */
	perl_script_module_t *m = mowgli_heap_alloc(perl_script_module_heap);
	mowgli_strlcpy(m->filename, filename, sizeof(m->filename));

	snprintf(perl_error, sizeof(perl_error),  "Unknown error attempting to load perl script %s",
			filename);

	dSP;
	ENTER;

	SAVETMPS;
	PUSHMARK(SP);

	XPUSHs(newRV_noinc((SV*)get_cv("Atheme::Init::load_script", 0)));
	XPUSHs(sv_2mortal(newSVpv(filename, 0)));
	PUTBACK;

	int perl_return_count = call_pv("Atheme::Init::call_wrapper", G_EVAL | G_SCALAR);

	SPAGAIN;

	if (SvTRUE(ERRSV))
	{
		mowgli_strlcpy(perl_error, SvPV_nolen(ERRSV), sizeof(perl_error));
		goto fail;
	}
	if (1 != perl_return_count)
	{
		snprintf(perl_error, sizeof(perl_error), "Script load didn't return a package name");
		goto fail;
	}

	/* load_script should have returned the package name that was just
	 * loaded...
	 */
	const char *packagename = POPp;
	char info_varname[BUFSIZE];
	snprintf(info_varname, BUFSIZE, "%s::Info", packagename);

	/* ... so use that name to grab the script information hash...
	 */
	HV *info_hash = get_hv(info_varname, 0);
	if (!info_hash)
	{
		snprintf(perl_error, sizeof(perl_error), "Couldn't get package info hash %s", info_varname);
		goto fail;
	}

	/* ..., extract the canonical name...
	 */
	SV **name_var = hv_fetch(info_hash, "name", 4, 0);
	if (!name_var)
	{
		snprintf(perl_error, sizeof(perl_error), "Couldn't find canonical name in package info hash");
		goto fail;
	}

	mowgli_strlcpy(m->mod.name, SvPV_nolen(*name_var), sizeof(m->mod.name));

	/* ... and dependency list.
	 */
	SV **deplist_var = hv_fetch(info_hash, "depends", 7, 0);
	/* Not declaring this is legal... */
	if (deplist_var)
	{
		/* ... but having it as anything but an arrayref isn't. */
		if (!SvROK(*deplist_var) || SvTYPE(SvRV(*deplist_var)) != SVt_PVAV)
		{
			snprintf(perl_error, sizeof(perl_error), "$Info::depends must be an array reference");
			goto fail;
		}

		AV *deplist = (AV*)SvRV(*deplist_var);
		I32 len = av_len(deplist);
		/* av_len returns max index, not number of items */
		for (I32 i = 0; i <= len; ++i)
		{
			SV **item = av_fetch(deplist, i, 0);
			if (!item)
				continue;
			const char *dep_name = SvPV_nolen(*item);
			if (!module_request(dep_name))
			{
				snprintf(perl_error, sizeof(perl_error), "Dependent module %s failed to load",
						dep_name);
				goto fail;
			}
			module_t *dep_mod = module_find_published(dep_name);
			mowgli_node_add(dep_mod, mowgli_node_create(), &m->mod.deplist);
			mowgli_node_add(m, mowgli_node_create(), &dep_mod->dephost);
		}
	}

	FREETMPS;
	LEAVE;
	invalidate_object_references();

	/* Now that everything's loaded, do the module housekeeping stuff. */
	m->mod.unload_handler = perl_script_module_unload_handler;
	/* Can't do much better than the address of the module_t here */
	m->mod.address = m;
	m->mod.can_unload = MODULE_UNLOAD_CAPABILITY_OK;
	return (module_t*)m;

fail:
	slog(LG_ERROR, "Failed to load Perl script %s: %s", filename, perl_error);

	if (info_hash)
		SvREFCNT_dec((SV*)info_hash);

	do_script_unload(filename);

	mowgli_heap_free(perl_script_module_heap, m);
	POPs;

	FREETMPS;
	LEAVE;

	invalidate_object_references();

	return NULL;
}