X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/f14e4f83088ec0316a241872d798fe8c58fca061..af40e58b1f72e7ab8a8131f4ec68cae998cc57b1:/src/proto-common.c diff --git a/src/proto-common.c b/src/proto-common.c index 0cff85a..2d8e1f8 100644 --- a/src/proto-common.c +++ b/src/proto-common.c @@ -3,9 +3,9 @@ * * This file is part of x3. * - * srvx is free software; you can redistribute it and/or modify + * x3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -23,6 +23,8 @@ #include "ioset.h" #include "log.h" #include "nickserv.h" +#include "spamserv.h" +#include "shun.h" #include "timeq.h" #ifdef HAVE_SYS_SOCKET_H #include @@ -51,12 +53,6 @@ extern struct cManagerNode cManager; extern unsigned long burst_length; extern struct cManagerNode cManager; extern struct policer_params *oper_policer_params, *luser_policer_params; -extern server_link_func_t *slf_list; -extern unsigned int slf_size, slf_used; -extern new_user_func_t *nuf_list; -extern unsigned int nuf_size, nuf_used; -extern del_user_func_t *duf_list; -extern unsigned int duf_size, duf_used; extern time_t boot_time; void received_ping(void); @@ -69,6 +65,7 @@ typedef void (*foreach_nonchan) (char *name, void *data); typedef void (*foreach_userfunc) (struct userNode *user, void *data); typedef void (*foreach_nonuser) (char *name, void *data); static void parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data); +static void call_channel_mode_funcs(struct userNode *who, struct chanNode *channel, char **modes, unsigned int argc); static void uplink_readable(struct io_fd *fd) { @@ -92,7 +89,7 @@ uplink_readable(struct io_fd *fd) { void socket_destroyed(struct io_fd *fd) { - if (fd && fd->eof) + if (fd && fd->state != IO_CONNECTED) log_module(MAIN_LOG, LOG_ERROR, "Connection to server lost."); socket_io_fd = NULL; cManager.uplink->state = DISCONNECTED; @@ -105,7 +102,7 @@ void replay_event_loop(void) while (!quit_services) { if (!replay_connected) { /* this time fudging is to get some of the logging right */ - self->link = self->boot = now; + self->link_time = self->boot = now; cManager.uplink->state = AUTHENTICATING; irc_introduce(cManager.uplink->password); replay_connected = 1; @@ -134,7 +131,7 @@ create_socket_client(struct uplinkNode *target) log_module(MAIN_LOG, LOG_INFO, "Connecting to %s:%i...", addr, port); - socket_io_fd = ioset_connect((struct sockaddr*)cManager.uplink->bind_addr, sizeof(struct sockaddr), addr, port, 1, 0, NULL); + socket_io_fd = ioset_connect(cManager.uplink->bind_addr, cManager.uplink->bind_addr_len, addr, port, 1, 0, NULL); if (!socket_io_fd) { log_module(MAIN_LOG, LOG_ERROR, "Connection to uplink failed: %s (%d)", strerror(errno), errno); target->state = DISCONNECTED; @@ -144,7 +141,6 @@ create_socket_client(struct uplinkNode *target) socket_io_fd->readable_cb = uplink_readable; socket_io_fd->destroy_cb = socket_destroyed; socket_io_fd->line_reads = 1; - socket_io_fd->wants_reads = 1; log_module(MAIN_LOG, LOG_INFO, "Connection to server established."); cManager.uplink = target; target->state = AUTHENTICATING; @@ -275,7 +271,8 @@ close_socket(void) replay_connected = 0; socket_destroyed(socket_io_fd); } else { - ioset_close(socket_io_fd->fd, 1); + ioset_close(socket_io_fd, 3); + socket_io_fd = NULL; } } @@ -412,6 +409,7 @@ recalc_bursts(struct server *eob_server) static struct chanmsg_func { chanmsg_func_t func; struct userNode *service; + void *extra; } chanmsg_funcs[256]; /* indexed by trigger character */ static struct allchanmsg_func { @@ -431,7 +429,7 @@ privmsg_chan_helper(struct chanNode *cn, void *data) { struct privmsg_desc *pd = data; struct modeNode *mn; - struct chanmsg_func *cf = &chanmsg_funcs[(unsigned char)pd->text[0]]; + struct chanmsg_func *cf; int x; /* Don't complain if it can't find the modeNode because the channel might @@ -440,9 +438,11 @@ privmsg_chan_helper(struct chanNode *cn, void *data) mn->idle_since = now; /* Never send a NOTICE to a channel to one of the services */ - if (!pd->is_notice && cf->func - && ((cn->modes & MODE_REGISTERED) || GetUserMode(cn, cf->service))) - cf->func(pd->user, cn, pd->text+1, cf->service); + cf = &chanmsg_funcs[(unsigned char)pd->text[0]]; + if (!pd->is_notice && cf->func) + cf->func(pd->user, cn, pd->text+1, cf->service, pd->is_notice, cf->extra); + else + spamserv_channel_message(cn, pd->user, pd->text); /* This catches *all* text sent to the channel that the services server sees */ for (x = 0; x < ALLCHANMSG_FUNCS_MAX; x++) { @@ -450,7 +450,7 @@ privmsg_chan_helper(struct chanNode *cn, void *data) if (!cf->func) break; /* end of list */ else - cf->func(pd->user, cn, pd->text, cf->service); + cf->func(pd->user, cn, pd->text, cf->service, pd->is_notice, cf->extra); } } @@ -464,19 +464,40 @@ privmsg_invalid(char *name, void *data) irc_numeric(pd->user, ERR_NOSUCHNICK, "%s@%s :No such nick", name, self->name); } +struct part_desc { + struct userNode *user; + const char *text; +}; + static void part_helper(struct chanNode *cn, void *data) { - DelChannelUser(data, cn, false, 0); + struct part_desc *desc = data; + DelChannelUser(desc->user, cn, desc->text, false); +} + +static CMD_FUNC(cmd_part) +{ + struct part_desc desc; + + if (argc < 2) + return 0; + desc.user = GetUserH(origin); + if (!desc.user) + return 0; + desc.text = (argc > 2) ? argv[argc - 1] : NULL; + parse_foreach(argv[1], part_helper, NULL, NULL, NULL, &desc); + return 1; } void -reg_chanmsg_func(unsigned char prefix, struct userNode *service, chanmsg_func_t handler) +reg_chanmsg_func(unsigned char prefix, struct userNode *service, chanmsg_func_t handler, void *extra) { if (chanmsg_funcs[prefix].func) log_module(MAIN_LOG, LOG_WARNING, "Re-registering new chanmsg handler for character `%c'.", prefix); chanmsg_funcs[prefix].func = handler; chanmsg_funcs[prefix].service = service; + chanmsg_funcs[prefix].extra = extra; } void @@ -499,21 +520,59 @@ get_chanmsg_bot(unsigned char prefix) } static mode_change_func_t *mcf_list; +static void **mcf_list_extra; static unsigned int mcf_size = 0, mcf_used = 0; void -reg_mode_change_func(mode_change_func_t handler) +reg_mode_change_func(mode_change_func_t handler, void *extra) { if (mcf_used == mcf_size) { if (mcf_size) { - mcf_size <<= 1; - mcf_list = realloc(mcf_list, mcf_size*sizeof(mode_change_func_t)); + mcf_size <<= 1; + mcf_list = realloc(mcf_list, mcf_size*sizeof(mode_change_func_t)); + mcf_list_extra = realloc(mcf_list_extra, mcf_size*sizeof(void*)); } else { - mcf_size = 8; - mcf_list = malloc(mcf_size*sizeof(mode_change_func_t)); + mcf_size = 8; + mcf_list = malloc(mcf_size*sizeof(mode_change_func_t)); + mcf_list_extra = malloc(mcf_size*sizeof(void*)); } } - mcf_list[mcf_used++] = handler; + mcf_list[mcf_used] = handler; + mcf_list_extra[mcf_used++] = extra; +} + +static oper_func_t *of_list; +static void **of_list_extra; +static unsigned int of_size = 0, of_used = 0; + +void +reg_oper_func(oper_func_t handler, void *extra) +{ + if (of_used == of_size) { + if (of_size) { + of_size <<= 1; + of_list = realloc(of_list, of_size*sizeof(oper_func_t)); + of_list_extra = realloc(of_list_extra, of_size*sizeof(void*)); + } else { + of_size = 8; + of_list = malloc(of_size*sizeof(oper_func_t)); + of_list_extra = malloc(of_size*sizeof(void*)); + } + } + of_list[of_used] = handler; + of_list_extra[of_used++] = extra; +} + +static void +call_oper_funcs(struct userNode *user) +{ + unsigned int n; + if (IsLocal(user)) + return; + for (n=0; (ndead; n++) + { + of_list[n](user, of_list_extra[n]); + } } struct mod_chanmode * @@ -543,6 +602,8 @@ mod_chanmode_dup(struct mod_chanmode *orig, unsigned int extra) res->modes_clear = orig->modes_clear; res->new_limit = orig->new_limit; memcpy(res->new_key, orig->new_key, sizeof(res->new_key)); + memcpy(res->new_upass, orig->new_upass, sizeof(res->new_upass)); + memcpy(res->new_apass, orig->new_apass, sizeof(res->new_apass)); res->argc = orig->argc; memcpy(res->args, orig->args, orig->argc*sizeof(orig->args[0])); } @@ -562,6 +623,10 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch channel->limit = change->new_limit; if (change->modes_set & MODE_KEY) strcpy(channel->key, change->new_key); + if (change->modes_set & MODE_UPASS) + strcpy(channel->upass, change->new_upass); + if (change->modes_set & MODE_APASS) + strcpy(channel->apass, change->new_apass); for (ii = 0; ii < change->argc; ++ii) { switch (change->args[ii].mode) { case MODE_BAN: @@ -626,13 +691,23 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch break; } break; + /* XXX Hack: this is the stupedest use of switch iv ever seen. + * you have to compare for EVERY POSSIBLE COMBINATION of bitmask + * because switch does only full comparison. This needs redone as if/else. + **/ case MODE_CHANOP: case MODE_HALFOP: case MODE_VOICE: + case MODE_VOICE|MODE_CHANOP: + case MODE_VOICE|MODE_HALFOP: + case MODE_CHANOP|MODE_HALFOP: case MODE_VOICE|MODE_CHANOP|MODE_HALFOP: case MODE_REMOVE|MODE_CHANOP: case MODE_REMOVE|MODE_HALFOP: case MODE_REMOVE|MODE_VOICE: + case MODE_REMOVE|MODE_VOICE|MODE_CHANOP: + case MODE_REMOVE|MODE_VOICE|MODE_HALFOP: + case MODE_REMOVE|MODE_CHANOP|MODE_HALFOP: case MODE_REMOVE|MODE_VOICE|MODE_CHANOP|MODE_HALFOP: if (change->args[ii].mode & MODE_REMOVE) change->args[ii].u.member->modes &= ~change->args[ii].mode; @@ -655,20 +730,30 @@ mod_chanmode_free(struct mod_chanmode *change) int mod_chanmode(struct userNode *who, struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags) { + struct modeNode *member; struct mod_chanmode *change; unsigned int ii; + short base_oplevel; + if (!modes || !modes[0]) return 0; - if (!(change = mod_chanmode_parse(channel, modes, argc, flags))) + if (who && (member = GetUserMode(channel, who))) + base_oplevel = member->oplevel; + else + base_oplevel = MAXOPLEVEL; + if (!(change = mod_chanmode_parse(channel, modes, argc, flags, base_oplevel))) return 0; + + call_channel_mode_funcs(who, channel, modes, argc); + if (flags & MC_ANNOUNCE) mod_chanmode_announce(who, channel, change); else mod_chanmode_apply(who, channel, change); if (flags & MC_NOTIFY) for (ii = 0; ii < mcf_used; ++ii) - mcf_list[ii](channel, who, change); + mcf_list[ii](channel, who, change, mcf_list_extra[ii]); mod_chanmode_free(change); return 1; } @@ -681,14 +766,102 @@ irc_make_chanmode(struct chanNode *chan, char *out) change.modes_set = chan->modes; change.new_limit = chan->limit; safestrncpy(change.new_key, chan->key, sizeof(change.new_key)); + safestrncpy(change.new_upass, chan->upass, sizeof(change.new_upass)); + safestrncpy(change.new_apass, chan->apass, sizeof(change.new_apass)); return strlen(mod_chanmode_format(&change, out)); } +static user_mode_func_t *um_list; +static void **um_list_extra; +static unsigned int um_size = 0, um_used = 0; + +void +reg_user_mode_func(user_mode_func_t handler, void *extra) +{ + if (um_used == um_size) { + if (um_size) { + um_size <<= 1; + um_list = realloc(um_list, um_size*sizeof(user_mode_func_t)); + um_list_extra = realloc(um_list_extra, um_size*sizeof(void*)); + } else { + um_size = 8; + um_list = malloc(um_size*sizeof(user_mode_func_t)); + um_list_extra = malloc(um_size*sizeof(void*)); + } + } + um_list[um_used] = handler; + um_list_extra[um_used++] = extra; +} + +void +unreg_user_mode_func(user_mode_func_t handler) +{ + unsigned int i; + for (i=0; ihostname; if (IsFakeHost(user) && IsHiddenHost(user) && !(options & GENMASK_NO_HIDING)) { hostname = user->fakehost; - } else if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) { - hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2); - sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix); + } else if (IsHiddenHost(user)) { + int style = 1; + char *data; + data = conf_get_data("server/hidden_host_type", RECDB_QSTRING); + if (data) + style = atoi(data); + + if ((style == 1) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) { + hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2); + sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix); + } else if ((style == 2) && !(options & GENMASK_NO_HIDING)) { + hostname = alloca(strlen(user->crypthost)); + sprintf(hostname, "%s", user->crypthost); + } } else if (options & GENMASK_STRICT_HOST) { if (options & GENMASK_BYIP) - hostname = inet_ntoa(user->ip); - } else if ((options & GENMASK_BYIP) || !hostname[strspn(hostname, "0123456789.")]) { - /* Should generate an IP-based hostmask. By popular acclaim, a /16 - * hostmask is used by default. */ - unsigned masked_ip, mask, masklen; - masklen = 16; - mask = ~0 << masklen; - masked_ip = ntohl(user->ip.s_addr) & mask; - hostname = alloca(32); - if (options & GENMASK_X3MASK) { - sprintf(hostname, "%d.%d.%d.%d/%d", (masked_ip>>24)&0xFF, (masked_ip>>16)&0xFF, (masked_ip>>8)&0xFF, masked_ip&0xFF, masklen); + hostname = (char*)irc_ntoa(&user->ip); + } else if ((options & GENMASK_BYIP) || irc_pton(&ip, NULL, hostname)) { + /* Should generate an IP-based hostmask. */ + hostname = alloca(IRC_NTOP_MAX_SIZE); + hostname[IRC_NTOP_MAX_SIZE-1] = '\0'; + if (irc_in_addr_is_ipv4(user->ip)) { + /* By popular acclaim, a /16 hostmask is used. */ + sprintf(hostname, "%d.%d.*", user->ip.in6_8[12], user->ip.in6_8[13]); + } else if (irc_in_addr_is_ipv6(user->ip)) { + /* Who knows what the default mask should be? Use a /48 to start with. */ + sprintf(hostname, "%x:%x:%x:*", user->ip.in6[0], user->ip.in6[1], user->ip.in6[2]); } else { - int ofs = 0; - for (ii=0; ii<4; ii++) { - if (masklen) { - ofs += sprintf(hostname+ofs, "%d.", (masked_ip>>24)&0xFF); - masklen -= 8; - masked_ip <<= 8; - } else { - ofs += sprintf(hostname+ofs, "*."); - } - } - /* Truncate the last . */ - hostname[ofs-1] = 0; + /* Unknown type; just copy IP directly. */ + irc_ntop(hostname, IRC_NTOP_MAX_SIZE, &user->ip); } } else { int cnt; @@ -759,8 +933,8 @@ generate_hostmask(struct userNode *user, int options) for (ii=cnt=0; hostname[ii]; ii++) if (hostname[ii] == '.') cnt++; - if (cnt == 1) { - /* only a two-level domain name; leave hostname */ + if (cnt == 0 || cnt == 1) { + /* only a one- or two-level domain name; leave hostname */ } else if (cnt == 2) { for (ii=0; user->hostname[ii] != '.'; ii++) ; /* Add 3 to account for the *. and \0. */ @@ -810,3 +984,22 @@ IsChannelName(const char *name) { } return 1; } + + +unsigned int +irc_user_modes(const struct userNode *user, char modes[], size_t length) +{ + unsigned int ii, jj; + + for (ii = jj = 0; (jj < length) && (irc_user_mode_chars[ii] != '\0'); ++ii) { + if ((user->modes & (1 << ii)) && (irc_user_mode_chars[ii] != ' ')) + modes[jj++] = irc_user_mode_chars[ii]; + } + + ii = jj; + while (jj < length) + modes[jj++] = '\0'; + + return ii; +} +