Esempio n. 1
0
/* Should we allow a given command? */
bool u_ratelimit_allow(u_user *user, u_ratelimit_cmd_t *deduct, const char *cmd)
{
	time_t lastrate, numtokens;

	if ((strcasecmp(cmd, "WHO") == 0) && (user->limit.whotokens > 0)) {
		/* Compensate for WHO */
		u_ratelimit_who_deduct(user);
		return true;
	}

	lastrate = NOW.tv_sec - user->limit.last;
	numtokens = lastrate / REFILLPERIOD;

	/* Update the last executed time */
	user->limit.last = NOW.tv_sec;

	/* Grant tokens if needed */
	user->limit.tokens += numtokens;
	if (user->limit.tokens > FLOODTOKENS)
		user->limit.tokens = FLOODTOKENS;

	/* Subtract tokens */
	if ((user->limit.tokens <= deduct->deduction) ||
	    (user->limit.tokens - deduct->deduction) == 0) {
		user->limit.tokens = 0;

		u_log(LG_WARN, "User %U flooding!", user);

		/* XXX do a kill */
		return false;
	}

	return true;
}
Esempio n. 2
0
static int mode_user(u_sourceinfo *si, char *s)
{
	u_modes m;
	u_mode_buf_stack stack;

	if (!s || !*s) {
		u_src_num(si, RPL_UMODEIS, u_user_modes(si->u));
		return 0;
	}

	m.ctx = &umodes;
	m.stacker = &u_mode_buf_stacker;
	m.setter = si;
	m.target = si->u;
	m.access = si;
	m.flags = SRC_IS_LOCAL_USER(si) ? 0 : MODE_FORCE_ALL;
	m.stack = &stack;

	u_mode_process(&m, 1, &s);

	if (stack.on != -1) {
		if (IS_LOCAL_USER(si->u)) {
			u_link_f(si->link, ":%U MODE %U %s%s",
			         si->u, si->u, stack.cbuf, stack.dbuf);
		}

		u_sendto_servers(si->link, ":%U MODE %U %s%s",
		                 si->u, si->u, stack.cbuf, stack.dbuf);
	}

	u_log(LG_VERBOSE, "%U now has user mode %s",
	      si->u, u_user_modes(si->u));

	return 0;
}
Esempio n. 3
0
File: tb.c Progetto: awilfox/tethys
static int c_s_tb(u_sourceinfo *si, u_msg *msg)
{
	char *chan = msg->argv[0];
	int ts;
	u_chan *c;

	msg->propagate = CMD_DO_BROADCAST;

	if (!(c = u_chan_get(chan))) {
		u_log(LG_WARN, "%I sent TB for nonexistent %s", si, chan);
		return 0;
	}

	ts = atoi(msg->argv[1]);
	/* TODO: TS checking */
	c->topic_time = ts;

	if (msg->argc > 3) {
		u_strlcpy(c->topic_setter, msg->argv[2], MAXNICKLEN+1);
	} else {
		snf(FMT_USER, c->topic_setter, MAXNICKLEN+1, "%I", si);
	}

	u_strlcpy(c->topic, msg->argv[msg->argc - 1], MAXTOPICLEN+1);

	u_sendto_chan(c, NULL, ST_USERS, ":%I TOPIC %C :%s", si, c, c->topic);

	return 0;
}
Esempio n. 4
0
static void cmode_stacker_send_list(u_modes *m)
{
	mowgli_list_t *list;

	if (!m->setter->u) {
		u_log(LG_WARN, "Tried to send list to non-user");
		return;
	}

	if (!(list = m->ctx->get_list(m, m->info))) {
		u_log(LG_SEVERE, "Can't send a list we don't have!!");
		return;
	}

	u_chan_send_list(m->target, m->setter->u, list);
}
Esempio n. 5
0
static int try_local_join_chan(u_sourceinfo *si, char *chan, char *key)
{
	u_chan *c, *fwd;
	u_chanuser *cu;
	bool created;
	int num;
	char *modes;

	/* verify entry */

	if (!(c = u_chan_get_or_create(chan)))
		return u_user_num(si->u, ERR_NOSUCHCHANNEL, chan);
	created = c->ts == NOW.tv_sec; /* is this ok? */

	if ((cu = u_chan_user_find(c, si->u)) != NULL)
		return 0;

	if ((num = u_entry_blocked(c, si->u, key)) != 0) {
		fwd = u_find_forward(c, si->u, key);
		if (fwd == NULL || u_chan_user_find(fwd, si->u))
			return u_user_num(si->u, num, c);
		c = fwd;
	}

	/* perform join */

	cu = u_chan_user_add(c, si->u);
	u_del_invite(c, si->u);
	if (created)
		cu->flags |= CU_PFX_OP;

	/* send messages */

	u_sendto_chan(c, NULL, ST_USERS, ":%H JOIN %C", si->u, c);

	modes = u_chan_modes(c, 1);
	if (created) {
		u_log(LG_VERBOSE, "Channel %C %s created by %U", c, modes, si->u);
		u_conn_f(si->link, ":%S MODE %C %s", &me, c, modes);
	}

	if (!(c->flags & CHAN_LOCAL)) {
		if (c->members->size == 1) {
			u_sendto_servers(NULL, ":%S SJOIN %u %C %s :%s%U",
			           &me, c->ts, c, modes,
			           (cu->flags & CU_PFX_OP) ? "@" : "", si->u);
		} else {
			u_sendto_servers(NULL, ":%U JOIN %u %C +",
			           si->u, c->ts, c);
		}
	}

	/* Credit them */
	u_ratelimit_who_credit(si->u);

	u_chan_send_topic(c, si->u);
	u_chan_send_names(c, si->u);

	return 0;
}
Esempio n. 6
0
void u_perror_real(const char *func, const char *s)
{
	int x = errno;
	char *error = strerror(x);

	u_log(LG_ERROR, "%s: %s: %s", func, s, error);
}
Esempio n. 7
0
u_link_origin *u_link_origin_create_from_fd(mowgli_eventloop_t *ev, int fd)
{
	const char *operation;
	u_link_origin *origin = NULL;

	/* Set the fd to be close-on-exec. All listening sockets will be closed when
	 * we upgrade. This may cause some slight disturbance for users currently
	 * connecting, but this is acceptable.
	 */
	operation = "set close-on-exec";
	if (set_cloexec(fd) < 0)
		goto error;

	u_log(LG_DEBUG, "u_link_origin_create_from_fd: %d", fd);

	origin = malloc(sizeof(*origin));

	operation = "create pollable";
	if (!(origin->poll = mowgli_pollable_create(ev, fd, origin))) {
		errno = -EINVAL; /* XXX */
		goto error;
	}

	mowgli_node_add(origin, &origin->n, &all_origins);
	mowgli_pollable_setselect(ev, origin->poll, MOWGLI_EVENTLOOP_IO_READ,
	                          accept_ready);

	return origin;
error:
	u_perror(operation);
	free(origin);
	return NULL;
}
Esempio n. 8
0
/* Serialization
 * -------------
 */
mowgli_json_t *u_link_to_json(u_link *link)
{
	mowgli_json_t *jl;

	if (!link)
		return NULL;

	jl = mowgli_json_create_object();
	json_oseti  (jl, "flags", link->flags);
	json_oseti  (jl, "type",  link->type);
	json_osets  (jl, "pass",  link->pass);
	json_oseti  (jl, "sendq", link->sendq);
	json_oseto  (jl, "ck_sendto", u_cookie_to_json(&link->ck_sendto));
	json_oseto  (jl, "conn",  u_conn_to_json(link->conn));
	json_osetb64(jl, "ibuf",  link->ibuf + link->ibufskip, link->ibuflen - link->ibufskip);

	switch (link->type) {
		case LINK_USER:
			/* we can figure this out when we restore */
			break;

		case LINK_SERVER:
			json_osets  (jl, "server_link_block_name", link->conf.link->name);
			break;

		default:
			u_log(LG_SEVERE, "unexpected link type %d", link->type);
			abort();
	}

	return jl;
}
Esempio n. 9
0
static int c_r_tmode(u_sourceinfo *si, u_msg *msg)
{
	char *target = msg->argv[1];
	int parc;
	char **parv;
	u_chan *c;
	u_modes m;
	struct cmode_stacker_private stack;

	if (!(c = u_chan_get(target))) {
		return u_log(LG_ERROR, "%G tried to TMODE nonexistent %s",
		             si->source, target);
	}

	if (atoi(msg->argv[0]) > c->ts)
		return 0;

	parc = msg->argc - 2;
	parv = msg->argv + 2;

	m.ctx = &cmodes;
	m.stacker = &cmode_stacker;
	m.setter = si;
	m.target = c;
	m.access = &me;
	m.stack = &stack;

	u_mode_process(&m, parc, parv);
	return 0;
}
Esempio n. 10
0
static u_chanuser *do_remote_join_chan(u_user *u, u_chan *c)
{
	u_chanuser *cu;

	if (IS_LOCAL_USER(u))
		u_log(LG_WARN, "do_remote_join_chan on local user %U", u);

	if ((cu = u_chan_user_find(c, u))) {
		u_log(LG_WARN, "Already have chanuser %U/%C; ignoring", u, c);
	} else if (!(cu = u_chan_user_add(c, u))) {
		u_log(LG_ERROR, "Could not create chanuser %U/%C", u, c);
		return NULL;
	}

	u_sendto_chan(c, NULL, ST_USERS, ":%H JOIN :%C", u, c);

	return cu;
}
Esempio n. 11
0
void u_udb_row_start(u_udb *db, char *name)
{
	if (db->reading) {
		u_log(LG_ERROR, "Tried to start row while reading database!");
		return;
	}

	db->sz = snf(FMT_LOG, db->line, UDB_LINE_SIZE, "%s", name);
}
Esempio n. 12
0
static void on_cleanup(u_conn *conn)
{
	u_log(LG_VERBOSE, "link: being cleaned up");

	if (conn->priv) {
		link_destroy(conn->priv);
		conn->priv = NULL;
	}
}
Esempio n. 13
0
static void on_connect_finish(u_conn *conn, int err)
{
	u_link *link = conn->priv;
	u_link_block *block = link->conf.link;

	u_log(LG_VERBOSE, "link: connect finished");

	u_server_burst_1(link, block);
}
Esempio n. 14
0
static void *conf_end(void *unused, void *unused2)
{
	if (all_origins.count != 0)
		return NULL;

	u_log(LG_WARN, "No listeners! Opening one on 6667");
	u_link_origin_create(base_ev, 6667);

	return NULL;
}
Esempio n. 15
0
int u_log_write_ex(int fac, int lev, int flags, int err, const char* file, 
    int line, const char *func, const char* fmt, ...)
{
    va_list ap;
    err_type savederr;
    int rc;
    char msg[U_MAX_LOG_LENGTH], strerr[STRERR_BUFSZ], errmsg[STRERR_BUFSZ];

    save_errno(savederr);

    /* build the message to send to the log system */
    va_start(ap, fmt); 
    rc = vsnprintf(msg, U_MAX_LOG_LENGTH, fmt, ap);
    va_end(ap);

    if(rc >= U_MAX_LOG_LENGTH)
        goto err; /* message too long */

    /* init empty strings */
    errmsg[0] = strerr[0] = 0;

    if(err)
    {
        u_strerror_r(err, strerr, sizeof(strerr));
        snprintf(errmsg, sizeof(errmsg), "[errno: %d, %s]", err, strerr);
        errmsg[sizeof(errmsg) - 1] = 0; /* paranoid set */
    } 

    /* ok, send the msg to the logger */
    if(flags & LOG_WRITE_FLAG_CTX)
        u_log(fac, lev, "[%s][%d:%s:%d:%s] %s %s", 
               u_log_label(lev), getpid(), file, line, func, msg, errmsg);
    else
        u_log(fac, lev, "[%s][%d:::] %s %s", 
               u_log_label(lev), getpid(), msg, errmsg);

    restore_errno(savederr);
    return 0;
err:
    restore_errno(savederr);
    return ~0;
}
Esempio n. 16
0
static void conf_listen_port(mowgli_config_file_t *cf,
                             mowgli_config_file_entry_t *ce)
{
	ushort low, hi;
	char buf[512];
	char *s, *lows, *his;

	mowgli_strlcpy(buf, ce->vardata, sizeof buf);

	lows = buf;
	his = NULL;

	if ((s = strstr(buf, "..")) || (s = strstr(buf, "-"))) {
		*s++ = '\0';
		while (*s && !isdigit(*s))
			s++;
		his = s;
	}

	low = atoi(lows);
	hi = (his && *his) ? atoi(his) : low;

	if (low == 0 || hi == 0) {
		u_log(LG_ERROR, "%s: invalid listen range string", ce->vardata);
		return;
	}

	if (hi < low) {
		u_log(LG_ERROR, "%u-%u: invalid listen range", low, hi);
		return;
	}

	if (hi - low > 20) {
		u_log(LG_ERROR, "%u-%u: listener range too large", low, hi);
		return;
	}

	for (; low <= hi; low++) {
		u_log(LG_DEBUG, "Listening on %u", low);
		u_link_origin_create(base_ev, low);
	}
}
Esempio n. 17
0
static void notice(u_user *u, const char *fmt, ...)
{
	char buf[512];
	va_list va;

	va_start(va, fmt);
	vsnf(FMT_USER, buf, 512, fmt, va);
	va_end(va);

	if (u == NULL) {
		/* ?? */
		u_log(LG_INFO, "notice: %s", buf);
	} else {
		u_link_f(u->link, ":%S NOTICE %U :%s", &me, u, buf);
	}
}
Esempio n. 18
0
char *u_udb_get_s(u_udb *db)
{
	char *s = db->buf;

	if (!db->reading) {
		u_log(LG_ERROR, "Tried to read word while writing database!");
		return NULL;
	}

	while (*db->p != ' ' && *db->p) {
		if (*db->p == '\\')
			db->p++;
		*s++ = *db->p++;
	}
	*s = '\0';

	return db->buf;
}
Esempio n. 19
0
u_link *u_link_connect(mowgli_eventloop_t *ev, u_link_block *block,
                       const struct sockaddr *addr, socklen_t addrlen)
{
	u_link *link = link_create();

	u_conn *conn;
	if (!(conn = u_conn_connect(ev, &u_link_conn_ctx, link, 0,
	                            addr, addrlen))) {
		link_destroy(link);
		return NULL;
	}

	link->conf.link = block;

	u_log(LG_VERBOSE, "connecting to %s", conn->ip);

	return link;
}
Esempio n. 20
0
static void accept_ready(mowgli_eventloop_t *ev, mowgli_eventloop_io_t *io,
                         mowgli_eventloop_io_dir_t dir, void *priv)
{
	mowgli_eventloop_pollable_t *poll = mowgli_eventloop_io_pollable(io);
	u_conn *conn;
	u_link *link;

	sync_time();

	link = link_create();

	if (!(conn = u_conn_accept(ev, &u_link_conn_ctx, link, 0, poll->fd))) {
		link_destroy(link);
		/* TODO: close listener, maybe? */
		return;
	}

	u_log(LG_VERBOSE, "new connection from %s", conn->ip);
}
Esempio n. 21
0
void u_link_vnum(u_link *link, const char *tgt, int num, va_list va)
{
	char buf[4096];
	char *fmt;

	if (!link)
		return;

	fmt = u_numeric_fmt[num];

	if (fmt == NULL) {
		u_log(LG_SEVERE, "Attempted to use NULL numeric %d", num);
		return;
	}

	/* numerics are ALWAYS FMT_USER */
	vsnf(FMT_USER, buf, 4096, fmt, va);

	u_link_f(link, ":%S %03d %s %s", &me, num, tgt, buf);
}
Esempio n. 22
0
int u_link_num(u_link *link, int num, ...)
{
	va_list va;

	if (!link)
		return 0;

	va_start(va, num);
	switch (link->type) {
	case LINK_NONE:
		u_link_vnum(link, "*", num, va);
		break;
	case LINK_USER:
		u_user_vnum(link->priv, num, va);
		break;
	default:
		u_log(LG_SEVERE, "Can't use u_link_num on type %d!", link->type);
	}
	va_end(va);

	return 0;
}
Esempio n. 23
0
void u_link_vf(u_link *link, const char *fmt, va_list va)
{
	uchar *buf;
	size_t sz;
	int type;

	if (!link)
		return;

	if (link->sendq > 0 && link->conn->sendq.size + 512 > link->sendq) {
		on_sendq_full(link->conn);
		return;
	}

	buf = u_conn_get_send_buffer(link->conn, 512);

	if (buf == NULL) {
		on_sendq_full(link->conn);
		return;
	}

	type = FMT_USER;
	if (link->type == LINK_SERVER)
		type = FMT_SERVER;

	sz = vsnf(type, (char*)buf, 510, fmt, va);

	buf[sz] = '\0';

	u_log(LG_DEBUG, "[%G] <- %s", link, buf);

	buf[sz++] = '\r';
	buf[sz++] = '\n';

	u_conn_end_send_buffer(link->conn, sz);
}
Esempio n. 24
0
static void dispatch_lines(u_link *link)
{
	uchar *buf;
	size_t buflen;
	uchar *s, *p;
	u_msg msg;

	buf = link->ibuf;
	buflen = link->ibuflen;

	/* i don't really ever comment my code, as it's mostly very straight
	   forward and relatively self-documenting. but C string processing
	   is typically very hairy stuff and it can be difficult to decipher
	   the intent of a chunk of code, so i commented it  --aji */

	buf[buflen] = '\0';

	while (buflen > 0) {
		/* check wait flags on every iteration, as line dispatch
		   can affect this */
		if (link->flags & U_LINK_WAIT)
			break;

		/* find the next \r and \n */
		s = memchr(buf, '\r', buflen);
		p = memchr(buf, '\n', buflen);

		/* if no line endings in buffer, we're done */
		if (!s && !p)
			break;

		/* if p is closer than s, then put p in s */
		if (!s || (p && p < s))
			s = p;
		/* s now contains the closest line ending */

		/* delete all contiguous line endings at s */
		for (p = s; *p == '\r' || *p == '\n'; p++)
			*p = '\0';
		/* p now points at the start of the next line */

		s = buf;
		buf = p;
		buflen = buflen - (p - s);
		/* s now points to the current line, and buf and buflen
		   describe the rest of the buffer */

		/* If executing this command causes an upgrade, u_cmd_invoke will not
		 * return. Indicate the length of the current message to the dump function
		 * so that it won't be serialized and re-execute after upgrade.
		 */
		link->ibufskip = (p - link->ibuf);

		/* dispatch the line */
		u_log(LG_DEBUG, "[%G] -> %s", link, s);
		if (u_msg_parse(&msg, (char*)s) < 0)
			continue;
		u_cmd_invoke(link, &msg, (char*)s);
	}

	/* move remaining buffer contents to the start of the in buffer */
	memmove(link->ibuf, link->ibuf + link->ibuflen - buflen, buflen);
	link->ibuflen = buflen;
	link->ibufskip = 0;
}
Esempio n. 25
0
u_link *u_link_from_json(mowgli_json_t *jl)
{
	u_link *link;
	mowgli_json_t *jcookie, *jconn;
	mowgli_string_t *jpass, *jslinkname;
	ssize_t sz;

	link = link_create();

	if (json_ogetu(jl, "flags", &link->flags) < 0)
		goto error;
	if (json_ogetu(jl, "type", &link->type) < 0)
		goto error;
	if (json_ogeti(jl, "sendq", &link->sendq) < 0)
		goto error;

	if ((sz = json_ogetb64(jl, "ibuf", link->ibuf, IBUFSIZE)) < 0)
		goto error;

	link->ibuflen = sz;
	link->ibuf[link->ibuflen] = '\0';

	jpass = json_ogets(jl, "pass");
	if (jpass) {
		link->pass = malloc(jpass->pos+1);
		memcpy(link->pass, jpass->str, jpass->pos);
		link->pass[jpass->pos] = '\0';
	}

	jcookie = json_ogeto(jl, "ck_sendto");
	if (!jcookie)
		goto error;

	if (u_cookie_from_json(jcookie, &link->ck_sendto) < 0)
		goto error;

	jconn = json_ogeto(jl, "conn");
	if (!jconn)
		goto error;

	link->conn = u_conn_from_json(base_ev, &u_link_conn_ctx, link, jconn);
	if (!link->conn)
		goto error;

	link->conn->priv = link;

	/* This must run after the config has been loaded. */
	switch (link->type) {
		case LINK_USER:
			/* If the user is post-registration, re-find his auth block. */
			if (link->flags & U_LINK_REGISTERED) {
				/* XXX: Should this be in user.c? */
				link->conf.auth = u_find_auth(link);
				if (!link->conf.auth)
					goto error;
			}

			break;

		case LINK_SERVER:
			jslinkname = json_ogets(jl, "server_link_block_name");
			if (!jslinkname)
				goto error;

			/* mowgli_string is NULL-terminated. We needn't care about NULLs. */
			link->conf.link = u_find_link(jslinkname->str);
			if (!link->conf.link)
				goto error;

			break;

		default:
			u_log(LG_SEVERE, "unexpected link type %d", link->type);
			abort();
	}

	return link;

error:
	if (link) {
		free(link->pass);
		free(link);
	}
	return NULL;
}