From: Michael Poole Date: Sat, 22 May 2004 04:24:57 +0000 (+0000) Subject: Add fake host support (assuming your ircd supports it) X-Git-Tag: v1.4.0-rc1~209 X-Git-Url: http://git.pk910.de/?p=srvx.git;a=commitdiff_plain;h=bf665239fc97c1a4cf32c75927390e6625a8b87c Add fake host support (assuming your ircd supports it) Add definitions in various places to support assigning fake hosts to users. We will not give you (or make for you) patches to make your ircd support this feature, so please do not ask. You must set a certain srvx.conf setting to be able to assign fakehosts; finding it is left as an exercise to the reader. git-archimport-id: srvx@srvx.net--2004-srvx/srvx--devo--1.3--patch-67 --- diff --git a/ChangeLog b/ChangeLog index e1d040b..34364d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,25 @@ # arch-tag: automatic-ChangeLog--srvx@srvx.net--2004-srvx/srvx--devo--1.3 # +2004-05-22 04:24:57 GMT Michael Poole patch-67 + + Summary: + Add fake host support (assuming your ircd supports it) + Revision: + srvx--devo--1.3--patch-67 + + Add definitions in various places to support assigning fake hosts to + users. We will not give you (or make for you) patches to make your + ircd support this feature, so please do not ask. You must set a + certain srvx.conf setting to be able to assign fakehosts; finding it + is left as an exercise to the reader. + + modified files: + ChangeLog src/chanserv.c src/hash.c src/hash.h src/log.c + src/nickserv.c src/nickserv.h src/opserv.c src/proto-bahamut.c + src/proto-common.c src/proto-p10.c src/proto.h src/tools.c + + 2004-05-22 03:00:05 GMT Michael Poole patch-66 Summary: diff --git a/src/chanserv.c b/src/chanserv.c index b347a8c..60f8991 100644 --- a/src/chanserv.c +++ b/src/chanserv.c @@ -3438,14 +3438,15 @@ cmd_list_users(struct userNode *user, struct chanNode *channel, unsigned int arg lData.lowest = lowest; lData.highest = highest; lData.search = (argc > 1) ? argv[1] : NULL; - send_list = zoot_list; + send_list = def_list; + (void)zoot_list; /* since it doesn't show user levels */ if(user->handle_info) { switch(user->handle_info->userlist_style) { case HI_STYLE_DEF: send_list = def_list; break; - case HI_STYLE_ZOOT: send_list = zoot_list; break; + case HI_STYLE_ZOOT: send_list = def_list; break; } } diff --git a/src/hash.c b/src/hash.c index 21bfa5f..439b68d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -238,6 +238,14 @@ StampUser(struct userNode *user, const char *stamp) user->modes |= FLAGS_STAMPED; } +void +assign_fakehost(struct userNode *user, const char *host, int announce) +{ + safestrncpy(user->fakehost, host, sizeof(user->fakehost)); + if (announce) + irc_fakehost(user, host); +} + static new_channel_func_t *ncf_list; static unsigned int ncf_size = 0, ncf_used = 0; diff --git a/src/hash.h b/src/hash.h index 41d3efd..d10c35e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -58,7 +58,7 @@ #define FLAGS_STAMPED 0x1000 /* for users who have been stamped */ #define FLAGS_HIDDEN_HOST 0x2000 /* user's host is masked by their account */ #define FLAGS_REGNICK 0x4000 /* user owns their current nick */ -#define FLAGS_REGISTERING 0x8000 /* user has issued accnt register command, is waiting for email cookie */ +#define FLAGS_REGISTERING 0x8000 /* user has issued account register command, is waiting for email cookie */ #define IsOper(x) ((x)->modes & FLAGS_OPER) #define IsService(x) ((x)->modes & FLAGS_SERVICE) @@ -75,6 +75,7 @@ #define IsHiddenHost(x) ((x)->modes & FLAGS_HIDDEN_HOST) #define IsReggedNick(x) ((x)->modes & FLAGS_REGNICK) #define IsRegistering(x) ((x)->modes & FLAGS_REGISTERING) +#define IsFakeHost(x) ((x)->fakehost[0] != '\0') #define IsLocal(x) ((x)->uplink == self) #define NICKLEN 30 @@ -101,6 +102,7 @@ struct userNode { char ident[USERLEN + 1]; /* Per-host identification for user */ char info[REALLEN + 1]; /* Free form additional client information */ char hostname[HOSTLEN + 1]; /* DNS name or IP address */ + char fakehost[HOSTLEN + 1]; /* Assigned fake host */ #ifdef WITH_PROTOCOL_P10 char numeric[COMBO_NUMERIC_LEN+1]; unsigned int num_local : 18; @@ -206,6 +208,7 @@ typedef void (*account_func_t) (struct userNode *user, const char *stamp); void reg_account_func(account_func_t handler); void call_account_func(struct userNode *user, const char *stamp); void StampUser(struct userNode *user, const char *stamp); +void assign_fakehost(struct userNode *user, const char *host, int announce); typedef void (*new_channel_func_t) (struct chanNode *chan); void reg_new_channel_func(new_channel_func_t handler); diff --git a/src/log.c b/src/log.c index 22804e8..f745700 100644 --- a/src/log.c +++ b/src/log.c @@ -244,7 +244,7 @@ find_severity(const char *text) * KEY := LOGSET '.' SEVSET * LOGSET := LOGLIT | LOGLIT ',' LOGSET * LOGLIT := a registered log type - * SEVSET := '*' | SEVLIT | '=' SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIT ',' SEVSET + * SEVSET := '*' | SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIT ',' SEVSET * SEVLIT := one of log_severity_names * A KEY contains the Cartesian product of the logs in its LOGSET * and the severities in its SEVSET. @@ -273,7 +273,8 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) int first; cont = strchr(buffer, ','); - if (cont) *cont++ = 0; + if (cont) + *cont++ = 0; if (buffer[0] == '*' && buffer[1] == 0) { for (bound = 0; bound < LOG_NUM_SEVERITIES; bound++) { /* make people explicitly specify replay targets */ diff --git a/src/nickserv.c b/src/nickserv.c index 68e42fe..4d7b374 100644 --- a/src/nickserv.c +++ b/src/nickserv.c @@ -47,6 +47,9 @@ #define KEY_DB_BACKUP_FREQ "db_backup_freq" #define KEY_MODOPER_LEVEL "modoper_level" #define KEY_SET_EPITHET_LEVEL "set_epithet_level" +#define KEY_SET_TITLE_LEVEL "set_title_level" +#define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level" +#define KEY_TITLEHOST_SUFFIX "titlehost_suffix" #define KEY_FLAG_LEVELS "flag_levels" #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq" #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq" @@ -93,6 +96,7 @@ #define KEY_TABLE_WIDTH "table_width" #define KEY_ANNOUNCEMENTS "announcements" #define KEY_MAXLOGINS "maxlogins" +#define KEY_FAKEHOST "fakehost" #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" @@ -174,6 +178,8 @@ static const struct message_entry msgtab[] = { { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." }, { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." }, { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." }, + { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." }, + { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." }, { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" }, { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" }, { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" }, @@ -189,6 +195,7 @@ static const struct message_entry msgtab[] = { { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" }, { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" }, { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" }, + { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" }, { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" }, { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" }, { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" }, @@ -278,6 +285,8 @@ static const struct message_entry msgtab[] = { { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" }, { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" }, { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" }, + { "NSMSG_SET_TITLE", "$bTITLE: $b%s" }, + { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" }, { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" }, { "NSEMAIL_ACTIVATION_BODY", "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n %2$s\nTo verify your email address and complete the account registration, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nThis command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n /msg %3$s@%4$s AUTH %5$s your-password\n Please remember to fill in 'your-password' with the actual password you gave to us when you registered.\n\nIf you did NOT request this account, you do not need to do anything. Please contact the %1$s staff if you have questions, and be sure to check our website." }, { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" }, @@ -327,6 +336,8 @@ static struct { unsigned long nochan_handle_expire_delay; unsigned long modoper_level; unsigned long set_epithet_level; + unsigned long set_title_level; + unsigned long set_fakehost_level; unsigned long handles_per_email; unsigned long email_search_level; const char *network_name; @@ -494,6 +505,7 @@ free_handle_info(void *vhi) delete_nick(hi->nicks); free(hi->infoline); free(hi->epithet); + free(hi->fakehost); if (hi->cookie) { timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0); nickserv_free_cookie(hi->cookie); @@ -815,6 +827,36 @@ reg_handle_rename_func(handle_rename_func_t func) rf_list[rf_list_used++] = func; } +static char * +generate_fakehost(struct handle_info *handle) +{ + extern const char *hidden_host_suffix; + static char buffer[HOSTLEN+1]; + + if (!handle->fakehost) { + snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix); + return buffer; + } else if (handle->fakehost[0] == '.') { + /* A leading dot indicates the stored value is actually a title. */ + snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix); + return buffer; + } + return handle->fakehost; +} + +static void +apply_fakehost(struct handle_info *handle) +{ + struct userNode *target; + char *fake; + + if (!handle->users) + return; + fake = generate_fakehost(handle); + for (target = handle->users; target; target = target->next_authed) + assign_fakehost(target, fake, 1); +} + static void set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp) { @@ -871,6 +913,9 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp) if (IsHelper(user)) userList_append(&curr_helpers, user); + if (hi->fakehost || old_info) + apply_fakehost(hi); + if (stamp) { #ifdef WITH_PROTOCOL_BAHAMUT /* Stamp users with their account ID. */ @@ -1300,6 +1345,9 @@ static NICKSERV_FUNC(cmd_handleinfo) reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none)); } + if (hi->fakehost) + reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE"))); + if (hi->last_quit_host[0]) reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host); else @@ -1623,7 +1671,7 @@ static NICKSERV_FUNC(cmd_allowauth) /* Unauthenticated users might still have been stamped previously and could therefore have a hidden host; do not allow them to authenticate to an account. */ - send_message(target, nickserv, "NSMSG_USER_PREV_STAMP", target->nick); + reply("NSMSG_USER_PREV_STAMP", target->nick); return 0; } if (argc == 2) @@ -2380,6 +2428,70 @@ static OPTION_FUNC(opt_epithet) return 1; } +static OPTION_FUNC(opt_title) +{ + const char *title; + + if (!override) { + send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]); + return 0; + } + + if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) { + title = argv[1]; + if (strchr(title, '.')) { + send_message(user, nickserv, "NSMSG_TITLE_INVALID"); + return 0; + } + free(hi->fakehost); + if (!strcmp(title, "*")) { + hi->fakehost = NULL; + } else { + hi->fakehost = malloc(strlen(title)+2); + hi->fakehost[0] = '.'; + strcpy(hi->fakehost+1, title); + } + apply_fakehost(hi); + } else if (hi->fakehost && (hi->fakehost[0] == '.')) + title = hi->fakehost + 1; + else + title = NULL; + if (!title) + title = user_find_message(user, "MSG_NONE"); + send_message(user, nickserv, "NSMSG_SET_TITLE", title); + return 1; +} + +static OPTION_FUNC(opt_fakehost) +{ + const char *fake; + + if (!override) { + send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]); + return 0; + } + + if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) { + fake = argv[1]; + if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) { + send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID"); + return 0; + } + free(hi->fakehost); + if (!strcmp(fake, "*")) + hi->fakehost = NULL; + else + hi->fakehost = strdup(fake); + fake = hi->fakehost; + apply_fakehost(hi); + } else + fake = generate_fakehost(hi); + if (!fake) + fake = user_find_message(user, "MSG_NONE"); + send_message(user, nickserv, "NSMSG_SET_FAKEHOST", fake); + return 1; +} + static NICKSERV_FUNC(cmd_reclaim) { struct handle_info *hi; @@ -2580,6 +2692,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) { saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr); if (hi->epithet) saxdb_write_string(ctx, KEY_EPITHET, hi->epithet); + if (hi->fakehost) + saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost); if (hi->flags) { int ii, flen; @@ -3166,6 +3280,9 @@ nickserv_db_read_handle(const char *handle, dict_t obj) str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING); if (str) hi->epithet = strdup(str); + str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING); + if (str) + hi->fakehost = strdup(str); subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT); if (subdb) { const char *data, *type, *expires, *cookie_str; @@ -3319,7 +3436,8 @@ nickserv_conf_read(void) str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING); if (!str) str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING); - if (nickserv_conf.valid_handle_regex_set) regfree(&nickserv_conf.valid_handle_regex); + if (nickserv_conf.valid_handle_regex_set) + regfree(&nickserv_conf.valid_handle_regex); if (str) { int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB); nickserv_conf.valid_handle_regex_set = !err; @@ -3328,7 +3446,8 @@ nickserv_conf_read(void) nickserv_conf.valid_handle_regex_set = 0; } str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING); - if (nickserv_conf.valid_nick_regex_set) regfree(&nickserv_conf.valid_nick_regex); + if (nickserv_conf.valid_nick_regex_set) + regfree(&nickserv_conf.valid_nick_regex); if (str) { int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB); nickserv_conf.valid_nick_regex_set = !err; @@ -3358,6 +3477,10 @@ nickserv_conf_read(void) nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900; str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING); nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1; + str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING); + nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900; + str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING); + nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000; str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING); if (!str) str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING); @@ -3432,6 +3555,8 @@ nickserv_conf_read(void) nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1; str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING); nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600; + str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING); + nickserv_conf.titlehost_suffix = str ? str : "example.net"; str = conf_get_data("server/network", RECDB_QSTRING); nickserv_conf.network_name = str ? str : "some IRC network"; if (!nickserv_conf.auth_policer_params) { @@ -3678,6 +3803,10 @@ init_nickserv(const char *nick) dict_insert(nickserv_opt_dict, "ACCESS", opt_level); dict_insert(nickserv_opt_dict, "LEVEL", opt_level); dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet); + if (nickserv_conf.titlehost_suffix) { + dict_insert(nickserv_opt_dict, "TITLE", opt_title); + dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost); + } dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements); dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins); dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language); diff --git a/src/nickserv.h b/src/nickserv.h index 97d3fb3..9c1f6e9 100644 --- a/src/nickserv.h +++ b/src/nickserv.h @@ -86,6 +86,7 @@ struct handle_info { char *epithet; char *infoline; char *handle; + char *fakehost; #ifdef WITH_PROTOCOL_BAHAMUT unsigned long id; #endif diff --git a/src/opserv.c b/src/opserv.c index a38d836..a63c0e1 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -115,6 +115,7 @@ static const struct message_entry msgtab[] = { { "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" }, { "OSMSG_WHOIS_NICK", "Nick : %s" }, { "OSMSG_WHOIS_HOST", "Host : %s@%s" }, + { "OSMSG_WHOIS_FAKEHOST", "Fakehost: %s" }, { "OSMSG_WHOIS_IP", "Real IP : %s" }, { "OSMSG_WHOIS_MODES", "Modes : +%s " }, { "OSMSG_WHOIS_INFO", "Info : %s" }, @@ -397,7 +398,7 @@ static MODCMD_FUNC(cmd_ban) struct mod_chanmode change; struct userNode *victim; - change.modes_set = change.modes_clear = 0; + mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_BAN; if (is_ircmask(argv[1])) @@ -537,9 +538,8 @@ static MODCMD_FUNC(cmd_clearmodes) reply("OSMSG_NO_CHANNEL_MODES", channel->name); return 0; } - change.modes_set = 0; + mod_chanmode_init(&change); change.modes_clear = channel->modes; - change.argc = 0; modcmd_chanmode_announce(&change); reply("OSMSG_CLEARMODES_DONE", channel->name); return 1; @@ -966,7 +966,7 @@ static MODCMD_FUNC(cmd_kickall) * channel, we have to join it in temporarily. */ if (!(inchan = GetUserMode(channel, bot) ? 1 : 0)) { struct mod_chanmode change; - memset(&change, 0, sizeof(change)); + mod_chanmode_init(&change); change.args[0].mode = MODE_CHANOP; change.args[0].member = AddChannelUser(bot, channel); modcmd_chanmode_announce(&change); @@ -1015,7 +1015,7 @@ static MODCMD_FUNC(cmd_kickban) reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); return 0; } - change.modes_set = change.modes_clear = 0; + mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_BAN; change.args[0].hostmask = mask = generate_hostmask(target, 0); @@ -1169,6 +1169,8 @@ static MODCMD_FUNC(cmd_whois) } reply("OSMSG_WHOIS_NICK", target->nick); reply("OSMSG_WHOIS_HOST", target->ident, target->hostname); + if (IsFakeHost(target)) + reply("OSMSG_WHOIS_FAKEHOST", target->fakehost); reply("OSMSG_WHOIS_IP", inet_ntoa(target->ip)); if (target->modes) { bpos = 0; @@ -1206,7 +1208,7 @@ static MODCMD_FUNC(cmd_whois) static MODCMD_FUNC(cmd_unban) { struct mod_chanmode change; - change.modes_set = change.modes_clear = 0; + mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_REMOVE | MODE_BAN; change.args[0].hostmask = argv[1]; @@ -1875,7 +1877,7 @@ opserv_join_check(struct modeNode *mNode) /* Don't moderate the channel unless it is activated and the number of users in the channel is over the threshold. */ struct mod_chanmode change; - change.modes_set = change.modes_clear = change.argc = 0; + mod_chanmode_init(&change); channel->join_flooded = 1; if (opserv_conf.join_flood_moderate && (channel->members.used > opserv_conf.join_flood_moderate_threshold)) { if (!GetUserMode(channel, opserv)) { @@ -2280,7 +2282,7 @@ static MODCMD_FUNC(cmd_clone) reply("MSG_CHANNEL_UNKNOWN", argv[3]); return 0; } - change.modes_set = change.modes_clear = 0; + mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_CHANOP; change.args[0].member = GetUserMode(channel, clone); diff --git a/src/proto-bahamut.c b/src/proto-bahamut.c index d0828f1..84531b0 100644 --- a/src/proto-bahamut.c +++ b/src/proto-bahamut.c @@ -271,6 +271,12 @@ irc_account(struct userNode *user, const char *stamp) } } +void +irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host)) +{ + /* not supported in bahamut */ +} + void irc_regnick(struct userNode *user) { diff --git a/src/proto-common.c b/src/proto-common.c index 8f5f1b9..35fc9bd 100644 --- a/src/proto-common.c +++ b/src/proto-common.c @@ -576,7 +576,10 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch } bn = calloc(1, sizeof(*bn)); safestrncpy(bn->ban, change->args[ii].hostmask, sizeof(bn->ban)); - safestrncpy(bn->who, who->nick, sizeof(bn->who)); + if (who) + safestrncpy(bn->who, who->nick, sizeof(bn->who)); + else + safestrncpy(bn->who, "", sizeof(bn->who)); bn->set = now; banList_append(&channel->banlist, bn); break; @@ -668,7 +671,9 @@ generate_hostmask(struct userNode *user, int options) strcpy(ident+1, user->ident + ((*user->ident == '~')?1:0)); } hostname = user->hostname; - if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) { + 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 (options & GENMASK_STRICT_HOST) { diff --git a/src/proto-p10.c b/src/proto-p10.c index 046030a..b2aa696 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -39,6 +39,7 @@ #define CMD_EOB "END_OF_BURST" #define CMD_EOB_ACK "EOB_ACK" #define CMD_ERROR "ERROR" +#define CMD_FAKEHOST "FAKE" #define CMD_GET "GET" #define CMD_GLINE "GLINE" #define CMD_HASH "HASH" @@ -120,6 +121,7 @@ #define TOK_EOB "EB" #define TOK_EOB_ACK "EA" #define TOK_ERROR "Y" +#define TOK_FAKEHOST "FA" #define TOK_GET "GET" #define TOK_GLINE "GL" #define TOK_HASH "HASH" @@ -212,6 +214,7 @@ #define P10_EOB TYPE(EOB) #define P10_EOB_ACK TYPE(EOB_ACK) #define P10_ERROR TYPE(ERROR) +#define P10_FAKEHOST TYPE(FAKEHOST) #define P10_GET TYPE(GET) #define P10_GLINE TYPE(GLINE) #define P10_HASH TYPE(HASH) @@ -418,6 +421,12 @@ irc_account(struct userNode *user, const char *stamp) putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp); } +void +irc_fakehost(struct userNode *user, const char *host) +{ + putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host); +} + void irc_regnick(UNUSED_ARG(struct userNode *user)) { @@ -1006,6 +1015,18 @@ static CMD_FUNC(cmd_account) return 1; } +static CMD_FUNC(cmd_fakehost) +{ + struct userNode *user; + + if ((argc < 3) || !origin || !GetServerH(origin)) + return 0; + if (!(user = GetUserN(argv[1]))) + return 1; + assign_fakehost(user, argv[2], 0); + return 1; +} + static CMD_FUNC(cmd_burst) { extern int rel_age; @@ -1184,7 +1205,7 @@ static CMD_FUNC(cmd_topic) static CMD_FUNC(cmd_num_topic) { - static struct chanNode *cn; + struct chanNode *cn; if (!argv[0]) return 0; /* huh? */ @@ -1469,6 +1490,8 @@ init_parse(void) dict_insert(irc_func_dict, TOK_NICK, cmd_nick); dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account); dict_insert(irc_func_dict, TOK_ACCOUNT, cmd_account); + dict_insert(irc_func_dict, CMD_FAKEHOST, cmd_fakehost); + dict_insert(irc_func_dict, TOK_FAKEHOST, cmd_fakehost); dict_insert(irc_func_dict, CMD_PASS, cmd_pass); dict_insert(irc_func_dict, TOK_PASS, cmd_pass); dict_insert(irc_func_dict, CMD_PING, cmd_ping); @@ -1545,6 +1568,7 @@ init_parse(void) dict_insert(irc_func_dict, "331", cmd_num_topic); dict_insert(irc_func_dict, "332", cmd_num_topic); dict_insert(irc_func_dict, "333", cmd_num_topic); + dict_insert(irc_func_dict, "345", cmd_dummy); /* blah has been invited to blah */ dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */ /* ban list resetting */ /* "stats g" responses */ @@ -2008,6 +2032,18 @@ void mod_usermode(struct userNode *user, const char *mode_change) { call_account_func(user, tag); } break; + case 'f': + if (*word) { + char host[MAXLEN]; + unsigned int ii; + for (ii=0; (*word != ' ') && (*word != '\0'); ) + host[ii++] = *word++; + host[ii] = 0; + while (*word == ' ') + word++; + assign_fakehost(user, host, 0); + } + break; } #undef do_user_mode } diff --git a/src/proto.h b/src/proto.h index 23f76e6..d95144f 100644 --- a/src/proto.h +++ b/src/proto.h @@ -152,6 +152,7 @@ void irc_svsnick(struct userNode *from, struct userNode *target, const char *new /* account maintenance */ void irc_account(struct userNode *user, const char *stamp); void irc_regnick(struct userNode *user); +void irc_fakehost(struct userNode *user, const char *host); /* numeric messages */ void irc_numeric(struct userNode *user, unsigned int num, const char *format, ...); diff --git a/src/tools.c b/src/tools.c index 219d0af..161e9d2 100644 --- a/src/tools.c +++ b/src/tools.c @@ -340,6 +340,8 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick return match_ircglob(inet_ntoa(user->ip), glob); } else { /* The host part of the mask isn't IP-based */ + if (IsFakeHost(user) && match_ircglob(user->fakehost, glob)) + return 1; if (hidden_host_suffix && user->handle_info) { char hidden_host[HOSTLEN+1]; snprintf(hidden_host, sizeof(hidden_host), "%s.%s", user->handle_info->handle, hidden_host_suffix);