diff -uNr ircservices-5.0.50/Changes ircservices-5.0.51/Changes --- ircservices-5.0.50/Changes 2005-03-31 02:32:40 +0900 +++ ircservices-5.0.51/Changes 2005-04-03 09:39:38 +0900 @@ -1,5 +1,20 @@ Version 5.0 ----------- +2005/04/02 .51 convert-db now checks for more potential problems with the + imported databases before writing out the XML data. +2005/04/02 Fixed bugs when converting databases from old versions of + PTlink Services. +2005/04/01 Fixed handling of links to forbidden nicks when converting + Auspice databases. +2005/03/31 ChanServ KICK no longer allows Services opers to be kicked. +2005/03/31 Ensured that usermode +r is cleared from nicks which lose + their identification status (e.g. from FORBID/SUSPEND). +2005/03/31 NickServ SUSPEND now forces the user of the suspended + nick to change nicknames, as FORBID does. Reported by + Dionisios K. +2005/03/31 ChanServ now stops non-identified users from joining + channels with mode +R locked on. Suggested by + Dionisios K. 2005/03/29 .50 Fixed security hole in NickServ LISTLINKS allowing any user to view a nick's links. Reported by diff -uNr ircservices-5.0.50/docs/3.html ircservices-5.0.51/docs/3.html --- ircservices-5.0.50/docs/3.html 2005-02-23 02:57:56 +0900 +++ ircservices-5.0.51/docs/3.html 2005-03-31 18:19:08 +0900 @@ -904,7 +904,9 @@ TOPICLOCK channel option (set with SET TOPICLOCK), which prevents users from changing the channel topic except via the -TOPIC command. +TOPIC command. Note, however, that the KICK command will +not allow a user with Services operator or greater privileges (see +section 3-4-1) to be kicked.

The STATUS command allows a user to check the access level of another user on the channel. diff -uNr ircservices-5.0.50/docs/4.html ircservices-5.0.51/docs/4.html --- ircservices-5.0.50/docs/4.html 2004-09-02 14:00:25 +0900 +++ ircservices-5.0.51/docs/4.html 2005-03-31 18:20:39 +0900 @@ -1916,8 +1916,9 @@ command, if any. By default, limited to users with level 50 (AOP) access and above on the channel.

-Note that protected (+a) users cannot be kicked with this -command, even by the channel founder. +Note that protected (+a) users and IRC operators with +Services operator privileges cannot be kicked with this command, +even by the channel founder.


diff -uNr ircservices-5.0.50/lang/ru.l ircservices-5.0.51/lang/ru.l --- ircservices-5.0.50/lang/ru.l 2005-03-17 14:10:23 +0900 +++ ircservices-5.0.51/lang/ru.l 2005-03-31 04:30:32 +0900 @@ -2,7 +2,7 @@ # Russian language file. # -# IRC Services is copyright (c) 1996-2004 Andrew Church. +# IRC Services is copyright (c) 1996-2005 Andrew Church. # E-mail: # Parts written by Andrew Kempe and others. # This program is free but copyrighted software; see the file COPYING for diff -uNr ircservices-5.0.50/modes.c ircservices-5.0.51/modes.c --- ircservices-5.0.50/modes.c 2005-03-31 02:40:48 +0900 +++ ircservices-5.0.51/modes.c 2005-04-03 10:17:16 +0900 @@ -39,6 +39,7 @@ /* The following are initialized by mode_setup(): */ int32 usermode_reg; /* Usermodes applied to registered nicks */ int32 chanmode_reg; /* Chanmodes applied to registered chans */ +int32 chanmode_regonly; /* Chanmodes indicating regnick-only channels*/ int32 chanmode_opersonly; /* Chanmodes indicating oper-only channels */ int32 chanusermode_owner; /* Chanuser-modes applied to channel owner */ char chanmode_multiple[257]; /* Chanmodes that can be set multiple times */ @@ -92,6 +93,8 @@ uint32 tmp = (uint32) modelist[i].flag; if (modelist[i].info & MI_REGISTERED) chanmode_reg |= tmp; + if (modelist[i].info & MI_REGNICKS_ONLY) + chanmode_regonly |= tmp; if (modelist[i].info & MI_OPERS_ONLY) chanmode_opersonly |= tmp; if (modelist[i].info & MI_MULTIPLE) diff -uNr ircservices-5.0.50/modes.h ircservices-5.0.51/modes.h --- ircservices-5.0.50/modes.h 2005-03-31 02:40:48 +0900 +++ ircservices-5.0.51/modes.h 2005-04-03 10:17:16 +0900 @@ -32,11 +32,11 @@ uint32 info; /* What kind of mode this is (MI_* below) */ } ModeData; -#define MI_REGISTERED 0x01 /* Applied to all registered nicks/chans */ -#define MI_OPERS_ONLY 0x02 /* A channel that only opers may join */ -#define MI_MULTIPLE 0x04 /* Mode can be set multiple times (+b etc); - * only needed for channel modes */ -#define MI_CHANOWNER 0x08 /* Set for a channel owner (founder) */ +#define MI_REGISTERED 0x01 /* [UC] Applied to all regged nicks/chans */ +#define MI_OPERS_ONLY 0x02 /* [ C] Only opers may join */ +#define MI_MULTIPLE 0x04 /* [ C] Can be set multiple times (+b etc) */ +#define MI_CHANOWNER 0x08 /* [U ] Set for a channel owner (founder) */ +#define MI_REGNICKS_ONLY 0x10 /* [ C] Only registered/ID'd nicks may join */ /* These bits are available for private use by protocol modules: (see * Unreal module for an example of usage) */ @@ -59,6 +59,7 @@ /* The following are initialized by mode_setup(): */ extern int32 usermode_reg; /* Usermodes applied to registered nicks */ extern int32 chanmode_reg; /* Chanmodes applied to registered chans */ +extern int32 chanmode_regonly; /* Chanmodes indicating regnick-only channels*/ extern int32 chanmode_opersonly;/* Chanmodes indicating oper-only channels */ extern int32 chanusermode_owner;/* Chanuser-modes applied to channel owner */ extern char chanmode_multiple[];/* Chanmodes that can be set multiple times */ diff -uNr ircservices-5.0.50/modules/chanserv/chanserv.h ircservices-5.0.51/modules/chanserv/chanserv.h --- ircservices-5.0.50/modules/chanserv/chanserv.h 2005-03-31 02:40:50 +0900 +++ ircservices-5.0.51/modules/chanserv/chanserv.h 2005-04-03 10:17:17 +0900 @@ -143,6 +143,9 @@ /* Hide mode lock from INFO */ #define CI_HIDE_MLOCK 0x00008000 +/* All channel flags */ +#define CI_ALLFLAGS 0x0000FEFF + /*************************************************************************/ /* Indices for ci->levels[]: (DO NOT REORDER THESE unless you hack diff -uNr ircservices-5.0.50/modules/chanserv/check.c ircservices-5.0.51/modules/chanserv/check.c --- ircservices-5.0.50/modules/chanserv/check.c 2005-03-31 02:40:50 +0900 +++ ircservices-5.0.51/modules/chanserv/check.c 2005-04-03 10:17:17 +0900 @@ -327,6 +327,15 @@ goto kick; } + if ((ci->mlock_on & chanmode_regonly) && !user_identified(user)) { + /* User must have usermode_reg flags, i.e. be using a registered + * nick and have identified, in order to join a chanmode_regonly + * channel */ + mask = create_mask(user, 1); + reason = getstring(user->ngi, CHAN_NOT_ALLOWED_TO_JOIN); + goto kick; + } + if (user_recognized(user)) ngi = user->ngi; else diff -uNr ircservices-5.0.50/modules/chanserv/main.c ircservices-5.0.51/modules/chanserv/main.c --- ircservices-5.0.50/modules/chanserv/main.c 2005-03-31 02:40:50 +0900 +++ ircservices-5.0.51/modules/chanserv/main.c 2005-04-03 10:17:17 +0900 @@ -1357,6 +1357,11 @@ return; } } + /* Also prevent Services opers and above from being kicked */ + if (is_services_oper(target_user)) { + notice_lang(s_ChanServ, u, CHAN_KICK_PROTECTED, target, chan); + return; + } /* Construct reason string: "KICK by Nick" / "KICK by Nick (reason)" */ if (reason && !*reason) diff -uNr ircservices-5.0.50/modules/memoserv/memoserv.h ircservices-5.0.51/modules/memoserv/memoserv.h --- ircservices-5.0.50/modules/memoserv/memoserv.h 2005-03-31 02:40:53 +0900 +++ ircservices-5.0.51/modules/memoserv/memoserv.h 2005-04-03 10:17:17 +0900 @@ -26,6 +26,8 @@ #define MF_UNREAD 0x0001 /* Memo has not yet been read */ #define MF_EXPIREOK 0x0002 /* Memo may be expired */ +#define MF_ALLFLAGS 0x0003 /* All memo flags */ + struct memoinfo_ { Memo *memos; int16 memos_count; diff -uNr ircservices-5.0.50/modules/nickserv/main.c ircservices-5.0.51/modules/nickserv/main.c --- ircservices-5.0.50/modules/nickserv/main.c 2005-03-31 02:40:54 +0900 +++ ircservices-5.0.51/modules/nickserv/main.c 2005-04-03 10:17:17 +0900 @@ -1492,6 +1492,9 @@ notice_lang(s_NickServ, u, NICK_SUSPEND_SUCCEEDED, nick); if (readonly) notice_lang(s_NickServ, u, READ_ONLY_MODE); + /* If someone is using the nick, make them stop */ + if (ni->user) + validate_user(ni->user); } } diff -uNr ircservices-5.0.50/modules/nickserv/nickserv.h ircservices-5.0.51/modules/nickserv/nickserv.h --- ircservices-5.0.50/modules/nickserv/nickserv.h 2005-03-31 02:40:54 +0900 +++ ircservices-5.0.51/modules/nickserv/nickserv.h 2005-04-03 10:17:17 +0900 @@ -93,8 +93,6 @@ int16 language; /* Language selected by nickname owner (LANG_*) */ int16 timezone; /* Offset from UTC, in minutes */ - channame_t *channels; /* Array of names of channels currently registered */ - int16 channels_count; /* Number of channels currently registered */ int16 channelmax; /* Maximum number of registered channels allowed */ char **access; /* Array of access masks */ @@ -103,12 +101,15 @@ char **ajoin; /* Array of autojoin channel */ int16 ajoin_count; /* # of entries */ - MemoInfo memos; char **ignore; /* Array of memo ignore entries */ int16 ignore_count; /* # of entries */ + MemoInfo memos; + /* Online-only info: */ + channame_t *channels; /* Array of names of channels currently registered */ + int16 channels_count; /* Number of channels currently registered */ User **id_users; /* Users who have identified for this group (array) */ int id_users_count; time_t last_sendauth; /* Time of last SENDAUTH (mail-auth module) */ @@ -121,6 +122,7 @@ /* Nickname status flags: */ #define NS_VERBOTEN 0x0002 /* Nick may not be registered or used */ #define NS_NOEXPIRE 0x0004 /* Nick never expires */ +#define NS_PERMANENT 0x0006 /* All permanent flags */ /* The following flags are temporary: */ #define NS_KILL_HELD 0x8000 /* Nick is being held after a kill */ #define NS_GUESTED 0x4000 /* SVSNICK has been sent but nick has not @@ -153,6 +155,8 @@ #define NF_MEMO_FWD 0x00001000 /* Forward memos to E-mail address */ #define NF_MEMO_FWDCOPY 0x00002000 /* Save copy of forwarded memos */ +#define NF_ALLFLAGS 0x00003FFB /* All flags */ + /* Nickgroup OperServ privilege levels: */ #define NP_SERVOPER 0x1000 @@ -180,9 +184,11 @@ #define NICKGROUPINFO_INVALID ((NickGroupInfo *)PTR_INVALID) /* Authentication code reasons: */ +#define NICKAUTH_MIN NICKAUTH_REGISTER #define NICKAUTH_REGISTER 1 /* Newly registered */ #define NICKAUTH_SET_EMAIL 2 /* E-mail address changed */ #define NICKAUTH_SETAUTH 3 /* SETAUTH command used */ +#define NICKAUTH_MAX NICKAUTH_SETAUTH /*************************************************************************/ diff -uNr ircservices-5.0.50/modules/nickserv/util.c ircservices-5.0.51/modules/nickserv/util.c --- ircservices-5.0.50/modules/nickserv/util.c 2005-03-31 02:40:54 +0900 +++ ircservices-5.0.51/modules/nickserv/util.c 2005-04-03 10:17:17 +0900 @@ -396,6 +396,10 @@ ni->user = u; if ((ni->status & NS_VERBOTEN) || ngi->suspendinfo) { + if (usermode_reg) { + send_cmd(s_NickServ, "SVSMODE %s :-%s", u->nick, + mode_flags_to_string(usermode_reg, MODE_USER)); + } notice_lang(s_NickServ, u, NICK_MAY_NOT_BE_USED); notice_lang(s_NickServ, u, DISCONNECT_IN_1_MINUTE); add_ns_timeout(ni, TO_SEND_433, 40); @@ -456,6 +460,13 @@ } /* if (!ngi->authcode) */ + /* From here on down, the user is known to be not identified. Clear + * any "registered nick" mode from them. */ + if (usermode_reg) { + send_cmd(s_NickServ, "SVSMODE %s :-%s", u->nick, + mode_flags_to_string(usermode_reg, MODE_USER)); + } + is_recognized = (call_callback_1(module, cb_check_recognized, u) == 1); if (!(ngi->flags & NF_SECURE) && !ngi->authcode && is_recognized) { diff -uNr ircservices-5.0.50/modules/protocol/bahamut.c ircservices-5.0.51/modules/protocol/bahamut.c --- ircservices-5.0.50/modules/protocol/bahamut.c 2005-03-31 02:40:54 +0900 +++ ircservices-5.0.51/modules/protocol/bahamut.c 2005-04-03 10:17:18 +0900 @@ -65,7 +65,8 @@ }; static const struct modedata_init new_chanmodes[] = { - {'R', {0x00000100,0,0}}, /* Only identified users can join */ + {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}}, + /* Only identified users can join */ {'r', {0x00000200,0,0,0,MI_REGISTERED}}, /* Set for all registered channels */ {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */ diff -uNr ircservices-5.0.50/modules/protocol/dreamforge.c ircservices-5.0.51/modules/protocol/dreamforge.c --- ircservices-5.0.50/modules/protocol/dreamforge.c 2005-03-31 02:40:55 +0900 +++ ircservices-5.0.51/modules/protocol/dreamforge.c 2005-04-03 10:17:18 +0900 @@ -55,7 +55,8 @@ }; static const struct modedata_init new_chanmodes[] = { - {'R', {0x00000100,0,0}}, /* Only identified users can join */ + {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}}, + /* Only identified users can join */ {'r', {0x00000200,0,0,0,MI_REGISTERED}}, /* Set for all registered channels */ }; diff -uNr ircservices-5.0.50/modules/protocol/ptlink.c ircservices-5.0.51/modules/protocol/ptlink.c --- ircservices-5.0.50/modules/protocol/ptlink.c 2005-03-31 02:40:55 +0900 +++ ircservices-5.0.51/modules/protocol/ptlink.c 2005-04-03 10:17:18 +0900 @@ -81,7 +81,8 @@ }; static const struct modedata_init new_chanmodes[] = { - {'R', {0x00000100,0,0}}, /* Only identified users can join */ + {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}}, + /* Only identified users can join */ {'r', {0x00000200,0,0,0,MI_REGISTERED}}, /* Set for all registered channels */ {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */ diff -uNr ircservices-5.0.50/modules/protocol/trircd.c ircservices-5.0.51/modules/protocol/trircd.c --- ircservices-5.0.50/modules/protocol/trircd.c 2005-03-31 02:40:55 +0900 +++ ircservices-5.0.51/modules/protocol/trircd.c 2005-04-03 10:17:18 +0900 @@ -105,7 +105,8 @@ }; static const struct modedata_init new_chanmodes[] = { - {'R', {0x00000100,0,0}}, /* Only identified users can join */ + {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}}, + /* Only identified users can join */ {'r', {0x00000200,0,0,0,MI_REGISTERED}}, /* Set for all registered channels */ {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */ diff -uNr ircservices-5.0.50/modules/protocol/unreal.c ircservices-5.0.51/modules/protocol/unreal.c --- ircservices-5.0.50/modules/protocol/unreal.c 2005-03-31 02:40:55 +0900 +++ ircservices-5.0.51/modules/protocol/unreal.c 2005-04-03 10:17:18 +0900 @@ -184,7 +184,8 @@ */ static const struct modedata_init new_chanmodes[] = { - {'R', {0x00000100,0,0}}, /* Only identified users can join */ + {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}}, + /* Only identified users can join */ {'r', {0x00000200,0,0,0,MI_REGISTERED}}, /* Set for all registered channels */ {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */ diff -uNr ircservices-5.0.50/modules.h ircservices-5.0.51/modules.h --- ircservices-5.0.50/modules.h 2005-03-31 02:40:48 +0900 +++ ircservices-5.0.51/modules.h 2005-04-03 10:17:16 +0900 @@ -16,7 +16,7 @@ * program (structures, etc.) makes existing binary modules incompatible. * All modules MUST export a variable `module_version' which is initialized * to this constant! */ -#define MODULE_VERSION_CODE 0x050021 /* 5.0.33 */ +#define MODULE_VERSION_CODE 0x050033 /* 5.0.51 */ /*************************************************************************/ diff -uNr ircservices-5.0.50/tools/convert-db.c ircservices-5.0.51/tools/convert-db.c --- ircservices-5.0.50/tools/convert-db.c 2005-03-31 02:40:49 +0900 +++ ircservices-5.0.51/tools/convert-db.c 2005-04-03 10:17:16 +0900 @@ -406,26 +406,54 @@ /* Perform sanity checks on the data after it's been read in. */ +static void sanity_check_nicks(void); +static void sanity_check_nickgroups(void); +static void sanity_check_channels(void); +static void sanity_check_maskdata(void); + static void sanity_checks(void) { + sanity_check_nicks(); + sanity_check_nickgroups(); + sanity_check_channels(); + sanity_check_maskdata(); +} + +static void sanity_check_nicks(void) +{ NickInfo *ni; NickGroupInfo *ngi; - ChannelInfo *ci; + char *s; int i; - /* Check for non-forbidden nicknames with no nickgroup */ for (ni = first_nickinfo(); ni; ni = next_nickinfo()) { - if (!(ni->status & NS_VERBOTEN) && !ni->nickgroup) { + + /* Forbidden nicks should have no other data associated with them. */ + if (ni->status & NS_VERBOTEN) { + ni->status &= ~(NS_VERBOTEN); + ni->last_usermask = NULL; + ni->last_realmask = NULL; + ni->last_realname = NULL; + ni->last_quit = NULL; + ni->last_seen = 0; + if (ni->nickgroup) { + fprintf(stderr, "BUG: Forbidden nickname %s associated with" + " nickgroup %u! Clearing nickgroup field.\n", + ni->nick, ni->nickgroup); + ni->nickgroup = 0; + } + ni->id_stamp = 0; + continue; + } + + /* The nick isn't a forbidden nick. First make sure it has the + * right nickgroup. */ + if (!ni->nickgroup) { fprintf(stderr, "BUG: Nickname %s has no nickgroup! Deleting.\n", ni->nick); del_nickinfo(ni); - } - } - - /* Make sure every non-forbidden nick belongs to the right nickgroup */ - for (ni = first_nickinfo(); ni; ni = next_nickinfo()) { - if (ni->status & NS_VERBOTEN) continue; + } ngi = get_nickgroupinfo(ni->nickgroup); if (!ngi) { fprintf(stderr, "BUG: Nickname %s points to nonexistent nickgroup" @@ -443,10 +471,52 @@ del_nickinfo(ni); } } - } - /* Make sure nickgroups don't contain extra nicks. */ + /* Clear unknown flags. */ + ni->status &= NS_PERMANENT; + + /* Make sure usermasks actually have non-empty user and host parts. */ + if (ni->last_usermask) { + s = strchr(ni->last_usermask, '@'); + if (!s || s==ni->last_usermask || !s[1]) { + fprintf(stderr, "Last usermask for nickname %s isn't a valid" + " user@host mask, clearing.\n", ni->nick); + ni->last_usermask = NULL; + } + } + if (ni->last_realmask) { + s = strchr(ni->last_realmask, '@'); + if (!s || s==ni->last_realmask || !s[1]) { + fprintf(stderr, "Last real usermask for nickname %s isn't" + " a valid user@host mask, clearing.\n", ni->nick); + ni->last_realmask = NULL; + } + } + + /* Make sure last-seen time is not earlier than registered time. + * Allow zero, to accommodate cases where the nickname was + * registered by an outside entity without the user actually + * logging on. */ + if (ni->last_seen && ni->last_seen < ni->time_registered) { + fprintf(stderr, "Last-seen time for nickname %s is earlier than" + " registration time! Setting last-seen time to" + " registration time.\n", ni->nick); + ni->last_seen = ni->time_registered; + } + + } /* for all nicks */ +} + +static void sanity_check_nickgroups(void) +{ + NickInfo *ni; + NickGroupInfo *ngi; + char *s; + int i; + for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) { + + /* Make sure nickgroups don't contain extra nicks. */ ARRAY_FOREACH(i, ngi->nicks) { ni = get_nickinfo(ngi->nicks[i]); if (!ni) { @@ -454,50 +524,273 @@ " nickname %s! Removing nickname from group.\n", ngi->id, ngi->nicks[i]); ARRAY_REMOVE(ngi->nicks, i); + if (ngi->mainnick >= i) + ngi->mainnick--; i--; /* to make sure we don't skip any */ - if (ngi->nicks_count <= 0) - del_nickgroupinfo(ngi); } } - } - /* Check for non-forbidden channels with no founder */ + /* Check for empty nickgroups (possibly from extraneous nickname + * removal above). */ + if (ngi->nicks_count == 0) { + fprintf(stderr, "Removing empty nickgroup %u.\n", ngi->id); + del_nickgroupinfo(ngi); + continue; + } + + /* Make sure main nick is a valid index. */ + if (ngi->mainnick >= ngi->nicks_count) { + fprintf(stderr, "Invalid main nick index in nickgroup %u," + " resetting.\n", ngi->id); + ngi->mainnick = 0; + } + + /* If an authcode is set, make sure the reason is valid. If not, + * clear the auth-related fields. */ + if (ngi->authcode && (ngi->authreason < NICKAUTH_MIN + || ngi->authreason > NICKAUTH_MAX)) { + fprintf(stderr, "Authentication code set for nickgroup %u but" + " reason code invalid, setting to SETAUTH.\n", ngi->id); + ngi->authreason = NICKAUTH_SETAUTH; + } else { + ngi->authset = 0; + ngi->authreason = 0; + } + + /* Clear all unknown flags. */ + ngi->flags &= NF_ALLFLAGS; + + /* Make sure language setting is in range. */ + if ((ngi->language < 0 || ngi->language >= NUM_LANGS) + && ngi->language != LANG_DEFAULT + ) { + fprintf(stderr, "Invalid language set for nickgroup %u," + " resetting to default.\n", ngi->id); + ngi->language = LANG_DEFAULT; + } + + /* Make sure access, autojoin, and ignore counts are non-negative. */ + if (ngi->access_count < 0) { + fprintf(stderr, "BUG: Access entry count for nickgroup %u is" + " negative! Clearing.\n", ngi->id); + ngi->access = NULL; + ngi->access_count = 0; + } + if (ngi->ajoin_count < 0) { + fprintf(stderr, "BUG: Autojoin entry count for nickgroup %u is" + " negative! Clearing.\n", ngi->id); + ngi->ajoin = NULL; + ngi->ajoin_count = 0; + } + if (ngi->ignore_count < 0) { + fprintf(stderr, "BUG: Ignore entry count for nickgroup %u is" + " negative! Clearing.\n", ngi->id); + ngi->ignore = NULL; + ngi->ignore_count = 0; + } + + /* Make sure all access entries have non-empty user and host parts. */ + ARRAY_FOREACH (i, ngi->access) { + s = strchr(ngi->access[i], '@'); + if (!s || s==ngi->access[i] || !s[1]) { + fprintf(stderr, "Access entry %d for nickgroup %u isn't a" + " valid user@host mask, deleting.\n", i, ngi->id); + ARRAY_REMOVE(ngi->access, i); + i--; + } + } + + /* Make sure memo count is non-negative. */ + if (ngi->memos.memos_count < 0) { + fprintf(stderr, "BUG: Memo count for nickgroup %u is negative!" + " Clearing.\n", ngi->id); + ngi->memos.memos = NULL; + ngi->memos.memos_count = 0; + } + + /* Clear unknown flags from memos. */ + ARRAY_FOREACH (i, ngi->memos.memos) + ngi->memos.memos[i].flags &= MF_ALLFLAGS; + + } /* for all nickgroups */ +} + +static void sanity_check_channels(void) +{ + ChannelInfo *ci; + char *s; + int i; + for (ci = first_channelinfo(); ci; ci = next_channelinfo()) { - if (!(ci->flags & CI_VERBOTEN) && !ci->founder) { + + /* Forbidden channels should have no other data associated with + * them. */ + if (ci->flags & CI_VERBOTEN) { + ci->founder = 0; + ci->successor = 0; + memset(ci->founderpass, 0, sizeof(ci->founderpass)); + ci->desc = NULL; + ci->url = NULL; + ci->email = NULL; + ci->last_used = 0; + ci->last_topic = NULL; + memset(ci->last_topic_setter, 0, sizeof(ci->last_topic_setter)); + ci->last_topic_time = 0; + ci->flags &= ~(CI_VERBOTEN); + ci->suspendinfo = NULL; + ci->levels = NULL; + ci->access = NULL; + ci->access_count = 0; + ci->akick = NULL; + ci->akick_count = 0; + ci->mlock_on = NULL; + ci->mlock_off = NULL; + ci->mlock_limit = 0; + ci->mlock_key = NULL; + ci->mlock_link = NULL; + ci->mlock_flood = NULL; + ci->mlock_joindelay = 0; + ci->mlock_joinrate1 = 0; + ci->mlock_joinrate2 = 0; + ci->entry_message = NULL; + ci->memos.memos = NULL; + ci->memos.memos_count = 0; + ci->memos.memomax = MEMOMAX_DEFAULT; + continue; + } + + /* Channel is not forbidden. First make sure it has a (valid) + * founder. */ + if (!ci->founder) { fprintf(stderr, "BUG: Channel %s has no founder! Deleting.\n", ci->name); del_channelinfo(ci); + } else if (!get_nickgroupinfo(ci->founder)) { + fprintf(stderr, "BUG: Channel %s founder nickgroup %u is" + " missing! Deleting channel.\n", ci->name, ci->founder); + del_channelinfo(ci); + } + + /* Make sure that the successor is valid if set. */ + if (ci->successor && !get_nickgroupinfo(ci->successor)) { + fprintf(stderr, "BUG: Channel %s successor nickgroup %u is" + " missing! Clearing.", ci->name, ci->successor); + ci->successor = 0; + } + + /* Make sure last-used time is not earlier than registered time. + * Allow zero, to accommodate cases where the channel was + * registered by an outside entity. */ + if (ci->last_used && ci->last_used < ci->time_registered) { + fprintf(stderr, "Last-used time for channel %s is earlier than" + " registration time! Setting last-used time to" + " registration time.\n", ci->name); + ci->last_used = ci->time_registered; + } + + /* If there is no saved topic, clear the topic setter and time. */ + if (!ci->last_topic) { + memset(ci->last_topic_setter, 0, sizeof(ci->last_topic_setter)); + ci->last_topic_time = 0; + } + + /* Clear unknown flags. */ + ci->flags &= CI_ALLFLAGS; + + /* Check privilege level settings for vaility. */ + if (ci->levels) { + for (i = 0; i < CA_SIZE; i++) { + if (ci->levels[i] < ACCLEV_INVALID + || ci->levels[i] > ACCLEV_FOUNDER + ) { + fprintf(stderr, "Privilege level %d on channel %s is" + "invalid; resetting all levels to defaults.\n", + i, ci->name); + ci->levels = NULL; + break; + } + } } - } + + /* Check access level nickgroups and levels for validity. */ + ARRAY_FOREACH (i, ci->access) { + if (!ci->access[i].nickgroup) + continue; + if (!get_nickgroupinfo(ci->access[i].nickgroup)) { + fprintf(stderr, "BUG: Channel %s access entry %d has an" + " invalid nickgroup! Clearing.\n", ci->name, i); + ci->access[i].nickgroup = 0; + ci->access[i].level = 0; + } else if (ci->access[i].level <= ACCLEV_INVALID + || ci->access[i].level >= ACCLEV_FOUNDER) { + fprintf(stderr, "BUG: Channel %s access entry %d has an" + "out-of-range level (%d)! Clearing.\n", + ci->name, i, ci->access[i].level); + ci->access[i].nickgroup = 0; + ci->access[i].level = 0; + } + } + + /* Make sure all autokick entries have non-empty user and host + * parts. */ + ARRAY_FOREACH (i, ci->akick) { + if (!ci->akick[i].mask) + continue; + s = strchr(ci->akick[i].mask, '@'); + if (!s || s==ci->akick[i].mask || !s[1]) { + fprintf(stderr, "Autokick entry %d for channel %s isn't a" + " valid user@host mask, deleting.\n", i, ci->name); + ci->akick[i].mask = NULL; + } + } + + /* Make sure memo count is non-negative. */ + if (ci->memos.memos_count < 0) { + fprintf(stderr, "BUG: Memo count for channel %s is negative!" + " Clearing.\n", ci->name); + ci->memos.memos = NULL; + ci->memos.memos_count = 0; + } + + /* Clear unknown flags from memos. */ + ARRAY_FOREACH (i, ci->memos.memos) + ci->memos.memos[i].flags &= MF_ALLFLAGS; + + } /* for all channels */ /* Check that channel successors and access list entries have valid * nickgroup IDs, and that access levels are in range */ for (ci = first_channelinfo(); ci; ci = next_channelinfo()) { if (ci->flags & CI_VERBOTEN) continue; - if (ci->successor && !get_nickgroupinfo(ci->successor)) { - fprintf(stderr, "BUG: Channel %s successor is an invalid" - " nickgroup! Clearing.\n", ci->name); - ci->successor = 0; + } +} + +static void sanity_check_maskdata(void) +{ + MaskData *md; + char *s; + int i; + + /* Make sure all MaskData entries actually have masks allocated. */ + for (i = 0; i < 256; i++) { + for (md = first_maskdata(i); md; md = next_maskdata(i)) { + if (!md->mask) + del_maskdata(i, md); } - ARRAY_FOREACH (i, ci->access) { - if (ci->access[i].nickgroup) { - if (!get_nickgroupinfo(ci->access[i].nickgroup)) { - fprintf(stderr, "BUG: Channel %s access entry %d has" - " an invalid nickgroup! Clearing.\n", - ci->name, i); - ci->access[i].nickgroup = 0; - ci->access[i].level = 0; - } else if (ci->access[i].level <= ACCLEV_INVALID - || ci->access[i].level >= ACCLEV_FOUNDER) { - fprintf(stderr, "BUG: Channel %s access entry %d has" - " an out-of-range level (%d)! Clearing.\n", - ci->name, i, ci->access[i].level); - ci->access[i].nickgroup = 0; - ci->access[i].level = 0; - } - } + } + + /* Make sure every autokill has a valid user@host mask and a reason. */ + for (md = first_maskdata(MD_AKILL); md; md = next_maskdata(MD_AKILL)) { + s = strchr(md->mask, '@'); + if (!s || s==md->mask || !s[1]) { + fprintf(stderr, "Autokill %s isn't a valid user@host mask," + " deleting.\n", md->mask); + del_maskdata(MD_AKILL, md); + continue; } + if (!md->reason) + md->reason = "Reason unknown"; } } diff -uNr ircservices-5.0.50/tools/convert-ptlink.c ircservices-5.0.51/tools/convert-ptlink.c --- ircservices-5.0.50/tools/convert-ptlink.c 2005-03-31 02:40:50 +0900 +++ ircservices-5.0.51/tools/convert-ptlink.c 2005-04-03 10:17:16 +0900 @@ -71,7 +71,8 @@ if (ver >= 7) SAFE(read_buffer(authbuf, f)); SAFE(read_string(&ngi->url, f)); - SAFE(read_string(&s, f)); /* temporary, unauthed E-mail */ + if (ver >= 7) + SAFE(read_string(&s, f)); /* temporary, unauthed E-mail */ SAFE(read_string(&ngi->email, f)); SAFE(read_string(&s, f)); /* icq_number */ SAFE(read_string(&s, f)); /* location */ @@ -87,7 +88,8 @@ SAFE(read_int32(&tmp32, f)); /* last_identify */ SAFE(read_int32(&tmp32, f)); ni->last_seen = tmp32; - SAFE(read_int32(&tmp32, f)); /* last_email_request */ + if (ver >= 7) + SAFE(read_int32(&tmp32, f)); /* last_email_request */ SAFE(read_int32(&tmp32, f)); /* birth_date */ SAFE(read_int16(&tmp16, f)); /* status */ if (tmp16 & 0x0002) { @@ -287,7 +289,7 @@ { char filename[PATH_MAX+1]; dbFILE *f; - int i, j, c; + int i, j, c, C_MAX; ChannelInfo *ci; NickInfo *ni; signed char ch; @@ -309,7 +311,8 @@ SAFE(read_int32(&total, f)); count = 0; - for (i = 0; i < 65535; i++) { + C_MAX = (ver<9 ? 256 : 65535); + for (i = 0; i < C_MAX; i++) { char *s; while ((c = getc_db(f)) == 1) { diff -uNr ircservices-5.0.50/tools/convert-sirv.c ircservices-5.0.51/tools/convert-sirv.c --- ircservices-5.0.50/tools/convert-sirv.c 2005-03-31 02:40:50 +0900 +++ ircservices-5.0.51/tools/convert-sirv.c 2005-04-03 10:17:16 +0900 @@ -245,6 +245,18 @@ fprintf(stderr, "Warning: dropping nick %s linked to" " nonexistent nick %s\n", ni->nick, ni->last_usermask); del_nickinfo(ni); + } else if (ni2->status & NS_VERBOTEN) { + /* Auspice allows links to forbidden nicks; we don't + * (because forbidden nicks don't have nickgroups). + * Just make the nick forbidden. */ + ni->status = NS_VERBOTEN; + ni->last_usermask = NULL; + } else if (ni2->nickgroup == 0) { + fprintf(stderr, "BUG: link target %s of nick %s has no" + " no nickgroup, dropping both nicks\n", + ni2->nick, ni->nick); + del_nickinfo(ni); + del_nickinfo(ni2); } else { ni->last_usermask = ni2->last_usermask; ni->nickgroup = ni2->nickgroup; diff -uNr ircservices-5.0.50/version.sh ircservices-5.0.51/version.sh --- ircservices-5.0.50/version.sh 2005-03-31 02:32:46 +0900 +++ ircservices-5.0.51/version.sh 2005-04-03 09:36:10 +0900 @@ -6,7 +6,7 @@ # $PROGRAM is the string returned as the first part of a /VERSION reply, # and must not contain spaces. It is not used anywhere else. PROGRAM=ircservices -VERSION=5.0.50 +VERSION=5.0.51 # Increment Services build number if [ -f version.c ] ; then