+2007-07-12 Perry Lorier <isomer@undernet.org>
+ Reconsider how we manage modes before registration, to avoid stats
+ getting out of sync.
+
+ * ircd/s_user.c (set_user_mode): Add new parameter to set_user_mode to
+ ignore some modes.
+ (register_user): Use set_user_mode to parse default usermode for
+ users.
+
+ * ircd/m_user.c: Add extra parameter to set_user_mode call
+
+ * ircd/s_auth.c: Add extra parameter to set_user_mode call
+
+ * ircd/m_mode.c: Add extra parameter to set_user_mode call
+
+ * ircd/s_misc.c: Verify stats are consistant.
+
+ * include/s_user.h: Change prototype, add flag definitions.
+
+ * ircd/m_lusers.c (m_users): Assert that we're generating sane stats,
+ include "unknowns" in the total user connections to avoid negative
+ wrap arounds.
+
2007-07-12 Perry Lorier <isomer@undernet.org>
* ircd/m_user.c (m_luser): Fix broken RFC 2812 on connect user mode
#define MATCH_SERVER 1 /**< flag for relay_masked_message (etc) to indicate the mask matches a server name */
#define MATCH_HOST 2 /**< flag for relay_masked_message (etc) to indicate the mask matches host name */
+/* used for parsing user modes */
+#define ALLOWMODES_ANY 0 /**< Allow any user mode */
+#define ALLOWMODES_DEFAULT 1 /**< Only allow the subset of modes that are legit defaults */
+
/** Formatter function for send_user_info().
* @param who Client being displayed.
* @param sptr Client requesting information.
extern int hide_hostmask(struct Client *cptr, unsigned int flags);
extern int set_user_mode(struct Client *cptr, struct Client *sptr,
- int parc, char *parv[]);
+ int parc, char *parv[], int allow_modes);
extern int is_silenced(struct Client *sptr, struct Client *acptr);
extern int hunt_server_cmd(struct Client *from, const char *cmd,
const char *tok, struct Client *one,
"%s :%C", 2, parc, parv) != HUNTED_ISME)
return 0;
- send_reply(sptr, RPL_LUSERCLIENT, UserStats.clients - UserStats.inv_clients,
+ assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
+
+ send_reply(sptr, RPL_LUSERCLIENT,
+ UserStats.clients - UserStats.inv_clients + UserStats.unknowns,
UserStats.inv_clients, UserStats.servers);
if (longoutput && UserStats.opers)
send_reply(sptr, RPL_LUSEROP, UserStats.opers);
send_reply(sptr, ERR_USERSDONTMATCH);
return 0;
}
- return set_user_mode(cptr, sptr, parc, parv);
+ return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY);
}
ClrFlag(sptr, FLAG_TS8);
cli_name(cptr), cli_name(sptr));
return 0;
}
- return set_user_mode(cptr, sptr, parc, parv);
+ return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY);
}
ClrFlag(sptr, FLAG_TS8);
if ((mode_request = strtoul(parv[2], &term, 10)) != 0
&& term != NULL && *term == '\0')
{
+ char *invisible[4] = { NULL, NULL, "+i", NULL };
+ char *wallops[4] = { NULL, NULL, "+w" , NULL };
/* These bitmask values are codified in RFC 2812, showing
* ... well, something that is probably best not said.
*/
if (mode_request & 8)
- SetInvisible(cptr);
+ set_user_mode(cptr, sptr, 3, invisible, ALLOWMODES_ANY);
if (mode_request & 4)
- SetWallops(cptr);
+ set_user_mode(cptr, sptr, 3, wallops, ALLOWMODES_ANY);
}
else if (parv[2][0] == '+')
{
user_modes[1] = NULL;
user_modes[2] = parv[2];
user_modes[3] = NULL;
- set_user_mode(cptr, sptr, 3, user_modes);
+ set_user_mode(cptr, sptr, 3, user_modes, ALLOWMODES_ANY);
}
info = (EmptyString(parv[4])) ? "No Info" : parv[4];
{
if (params[0][0] == '+')
{
- set_user_mode(cli, cli, parc + 2, params - 2);
+ set_user_mode(cli, cli, parc + 2, params - 2, ALLOWMODES_ANY);
}
return 0;
}
if (MyUser(bcptr))
set_snomask(bcptr, ~0, SNO_DEL);
- if (IsInvisible(bcptr))
+ if (IsInvisible(bcptr)) {
+ assert(UserStats.inv_clients > 0);
--UserStats.inv_clients;
- if (IsOper(bcptr))
+ }
+ if (IsOper(bcptr)) {
+ assert(UserStats.opers > 0);
--UserStats.opers;
+ }
if (MyConnect(bcptr))
Count_clientdisconnects(bcptr, UserStats);
else
assert(0 == user->channel);
MyFree(user);
+ assert(userCount>0);
--userCount;
}
}
SetUser(sptr);
}
- if (IsInvisible(sptr))
- ++UserStats.inv_clients;
- if (IsOper(sptr))
- ++UserStats.opers;
/* If they get both +x and an account during registration, hide
* their hostmask here. Calling hide_hostmask() from IAuth's
* account assignment causes a numeric reply during registration.
* @param[in] sptr Client who sent the mode change message.
* @param[in] parc Number of parameters in \a parv.
* @param[in] parv Parameters to MODE.
+ * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for
+ * only permitting legitimate default user modes.
* @return Zero.
*/
-int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int set_user_mode(struct Client *cptr, struct Client *sptr, int parc,
+ char *parv[], int allow_modes)
{
char** p;
char* m;
if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr))
{
/* user no longer oper */
+ assert(UserStats.opers > 0);
--UserStats.opers;
client_set_privs(sptr, NULL); /* will clear propagate privilege */
}
- if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr))
+ if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
+ assert(UserStats.inv_clients > 0);
--UserStats.inv_clients;
+ }
if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr))
++UserStats.inv_clients;
- if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
+ if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
hide_hostmask(sptr, FLAG_HIDDENHOST);
if (IsRegistered(sptr))
send_umode_out(cptr, sptr, &setflags, prop);
+ assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
+ assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
return 0;
}