2 # Parent 37c9c74606033a6520033f95aa61690a8e4bcadd
4 # add REMOTEMODE (P10 token RM) allowing a service do change certain modes on users
5 # <source numeric server> RM <target numeric user> <mode changes and arguments> (note: no : prefixing last parameter)
6 # only allow +-diwRnIx, allow +h <user@host> and -h (so we dont need remote sethost/SH token anymore), other modes are not allowed to be set remotely
7 # usermode x can only be set, not unset (same as normal)
8 # usermode h can only be unset, if the user is +rx (or +r and allowed to set +x) - this prevents exposing the realhost out of the blue
9 # easy to add/remove modes
10 # REMOTEMODE travels from source server to victim server, from where a normal usermode change is broadcasted to the network
11 # unfortunately the code is a bit messy because of the sethost stuff, should we in the future accept the sethost.patch (see queue), it can be cleaned up quite a bit
12 # after snircd1.3.5 this patch will be moved further down in the patch queue, to clean up the sethost part, and add other usermodes such as +q
14 diff -r 37c9c7460603 include/handlers.h
15 --- a/include/handlers.h
16 +++ b/include/handlers.h
18 extern int ms_privs(struct Client*, struct Client*, int, char*[]);
19 extern int ms_quit(struct Client*, struct Client*, int, char*[]);
20 extern int ms_reburst(struct Client*, struct Client*, int, char*[]);
21 +extern int ms_remotemode(struct Client*, struct Client*, int, char*[]);
22 extern int ms_rping(struct Client*, struct Client*, int, char*[]);
23 extern int ms_rpong(struct Client*, struct Client*, int, char*[]);
24 extern int ms_server(struct Client*, struct Client*, int, char*[]);
25 diff -r 37c9c7460603 include/msg.h
29 #define TOK_REBURST "RB"
30 #define CMD_REBURST MSG_REBURST, TOK_REBURST
32 +#define MSG_REMOTEMODE "REMOTEMODE" /* REMOTEMODE */
33 +#define TOK_REMOTEMODE "RM"
34 +#define CMD_REMOTEMODE MSG_REMOTEMODE, TOK_REMOTEMODE
38 #define CMD_CAP MSG_CAP, TOK_CAP
39 diff -r 37c9c7460603 ircd/Makefile.in
40 --- a/ircd/Makefile.in
41 +++ b/ircd/Makefile.in
50 diff -r 37c9c7460603 ircd/m_remotemode.c
52 +++ b/ircd/m_remotemode.c
55 + * IRC - Internet Relay Chat, ircd/m_mode.c
56 + * Copyright (C) 1990 Jarkko Oikarinen and
57 + * University of Oulu, Computing Center
59 + * See file AUTHORS in IRC package for additional names of
62 + * This program is free software; you can redistribute it and/or modify
63 + * it under the terms of the GNU General Public License as published by
64 + * the Free Software Foundation; either version 1, or (at your option)
65 + * any later version.
67 + * This program is distributed in the hope that it will be useful,
68 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
69 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
70 + * GNU General Public License for more details.
72 + * You should have received a copy of the GNU General Public License
73 + * along with this program; if not, write to the Free Software
74 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
76 + * $Id: m_mode.c 1818 2007-07-14 02:40:01Z isomer $
80 + * m_functions execute protocol messages on this server:
82 + * cptr is always NON-NULL, pointing to a *LOCAL* client
83 + * structure (with an open socket connected!). This
84 + * identifies the physical socket where the message
85 + * originated (or which caused the m_function to be
86 + * executed--some m_functions may call others...).
88 + * sptr is the source of the message, defined by the
89 + * prefix part of the message if present. If not
90 + * or prefix not found, then sptr==cptr.
92 + * (!IsServer(cptr)) => (cptr == sptr), because
93 + * prefixes are taken *only* from servers...
96 + * (sptr == cptr) => the message didn't
99 + * (sptr != cptr && IsServer(sptr) means
100 + * the prefix specified servername. (?)
102 + * (sptr != cptr && !IsServer(sptr) means
103 + * that message originated from a remote
104 + * user (not local).
108 + * (!IsServer(sptr)) means that, sptr can safely
109 + * taken as defining the target structure of the
110 + * message in this server.
112 + * *Always* true (if 'parse' and others are working correct):
114 + * 1) sptr->from == cptr (note: cptr->from == cptr)
116 + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
117 + * *cannot* be a local connection, unless it's
118 + * actually cptr!). [MyConnect(x) should probably
119 + * be defined as (x == x->from) --msa ]
121 + * parc number of variable parameter strings (if zero,
122 + * parv is allowed to be NULL)
124 + * parv a NULL terminated list of parameter pointers,
126 + * parv[0], sender (prefix string), if not present
127 + * this points to an empty string.
128 + * parv[1]...parv[parc-1]
129 + * pointers to additional parameters
130 + * parv[parc] == NULL, *always*
132 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
133 + * non-NULL pointers.
138 +#include "channel.h"
140 +#include "ircd_features.h"
141 +#include "ircd_log.h"
142 +#include "ircd_reply.h"
143 +#include "ircd_string.h"
144 +#include "ircd_snprintf.h"
147 +#include "numeric.h"
148 +#include "querycmds.h"
150 +#include "s_debug.h"
154 +#include "numnicks.h"
159 + * ms_remotemode - remotemode server message handler
161 + * parv[0] = sender prefix
162 + * parv[1] = target user numeric
163 + * parv[2+] = mode and arguments
166 +int ms_remotemode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
169 + struct Client *acptr;
170 + struct Flags setflags;
171 + struct Membership *chan;
178 + char hiddenhost[USERLEN + HOSTLEN + 2];
179 + int what = MODE_ADD;
180 + int do_host_hiding = 0;
181 + int do_set_host = 0;
183 + /* not from a server */
184 + if (!IsServer(sptr))
185 + return protocol_violation(cptr, "Received REMOTEMODE from user %C", sptr);
187 + /* check paramaters */
189 + return protocol_violation(cptr, "Received too few parameters for REMOTEMODE from %C (got %d - need at least 3)", parc, sptr);
194 + if(!(acptr = findNUser(target)))
197 + /* TODO: how to pass along all params in an easy way? */
198 + /* not for my user, pass it along */
199 + if (!MyConnect(acptr)) {
200 + sendcmdto_one(sptr, CMD_REMOTEMODE, acptr, "%C %s %s %s %s %s %s %s %s %s %s %s %s %s", acptr,
202 + parc > 3 ? parv[3] : "",
203 + parc > 4 ? parv[4] : "",
204 + parc > 5 ? parv[5] : "",
205 + parc > 6 ? parv[6] : "",
206 + parc > 7 ? parv[7] : "",
207 + parc > 8 ? parv[8] : "",
208 + parc > 9 ? parv[9] : "",
209 + parc > 10 ? parv[10] : "",
210 + parc > 11 ? parv[11] : "",
211 + parc > 12 ? parv[12] : "",
212 + parc > 13 ? parv[13] : "",
213 + parc > 14 ? parv[14] : "");
218 + setflags = cli_flags(acptr);
220 + /* parse mode change string(s) */
221 + for (p = &parv[2]; *p && p<&parv[parc]; p++) { /* p is changed in loop too */
222 + for (m = *p; *m; m++) {
231 + if (what == MODE_ADD)
234 + ClearWallops(acptr);
237 + if (what == MODE_ADD)
238 + SetInvisible(acptr);
240 + ClearInvisible(acptr);
243 + if (what == MODE_ADD)
249 + if (what == MODE_ADD)
252 + ClearNoChan(acptr);
255 + if (what == MODE_ADD)
258 + ClearNoIdle(acptr);
261 + if (what == MODE_ADD)
262 + SetAccountOnly(acptr);
264 + ClearAccountOnly(acptr);
267 + if (what == MODE_ADD)
268 + do_host_hiding = 1;
271 + if (what == MODE_ADD) {
272 + if (*(p + 1) && is_hostmask(*(p + 1))) {
277 + protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr);
279 + protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr);
280 + p++; /* Swallow the arg anyway */
283 + } else { /* MODE_DEL */
290 + protocol_violation(sptr, "Received REMOTEMODE %c%c unknown user mode flag or disallowed to set remotely for user %C",
291 + what == MODE_ADD ? '+' : '-', *m, acptr);
297 + /* do host hiding for +x */
298 + if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
299 + hide_hostmask(acptr, FLAG_HIDDENHOST);
301 + /* sanity checks for -h */
302 + if (do_set_host && !hostmask) {
303 + /* user has no sethost or has no account
305 + * user has +h - their host is hidden, do not remove it
306 + * unless the user has an account set
307 + * we should not out of the blue expose the real host
309 + if (!IsSetHost(acptr) || !IsAccount(acptr))
312 + /* user not +x and not allowed to set it */
313 + else if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING))
318 + SetHiddenHost(acptr);
321 + /* sanity checks for +h */
322 + if (do_set_host && hostmask) {
323 + if ((host = strrchr(hostmask, '@'))) {
330 + /* check if new sethost is different from before */
331 + if (IsSetHost(acptr) &&
332 + (!user || strcmp(cli_user(acptr)->username, user) == 0) &&
333 + strcmp(cli_user(acptr)->host, host) == 0)
337 + /* do host hiding for +h/-h */
340 + /* quit user from channel */
341 + sendcmdto_common_channels_butone(acptr, CMD_QUIT, acptr, ":Host change");
346 + /* clear +h in old flags so +h is sent out again with new sethost param */
347 + FlagClr(&setflags, FLAG_SETHOST);
349 + ircd_strncpy(cli_user(acptr)->username, user, USERLEN);
350 + ircd_strncpy(cli_user(acptr)->host, host, HOSTLEN);
354 + ClearSetHost(acptr);
355 + ircd_strncpy(cli_user(acptr)->username, cli_user(acptr)->realusername, USERLEN);
356 + /* user is +rx - need to restore +x host */
357 + if (HasHiddenHost(acptr))
358 + ircd_snprintf(0, cli_user(acptr)->host, HOSTLEN, "%s.%s",
359 + cli_user(acptr)->account, feature_str(FEAT_HIDDEN_HOST));
361 + ircd_strncpy(cli_user(acptr)->host, cli_user(acptr)->realhost, HOSTLEN);
364 + /* inform user of hidden host */
365 + ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
366 + cli_user(acptr)->username, cli_user(acptr)->host);
367 + send_reply(acptr, RPL_HOSTHIDDEN, hiddenhost);
370 + * Go through all channels the client was on, rejoin him
371 + * and set the modes, if any
373 + for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel) {
374 + /* Invalidate bans against the user so we check them again */
375 + ClearBanValid(chan);
376 + if (IsZombie(chan))
378 + /* If this channel has delayed joins and the user has no modes, just set
379 + * the delayed join flag rather than showing the join, even if the user
380 + * was visible before */
381 + if (!IsChanOp(chan) && !HasVoice(chan)
382 + && (chan->channel->mode.mode & MODE_DELJOINS)) {
383 + SetDelayedJoin(chan);
385 + sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chan->channel, acptr, 0,
386 + "%H", chan->channel);
388 + if (IsChanOp(chan) && HasVoice(chan)) {
389 + sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, acptr, 0,
390 + "%H +ov %C %C", chan->channel, acptr, acptr);
391 + } else if (IsChanOp(chan) || HasVoice(chan)) {
392 + sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, acptr, 0,
393 + "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', acptr);
398 + /* adjust count for invisible/visible users */
399 + if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(acptr)) {
400 + assert(UserStats.inv_clients > 0);
401 + --UserStats.inv_clients;
403 + if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(acptr)) {
404 + ++UserStats.inv_clients;
406 + assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
408 + /* send out the mode */
409 + send_umode_out(acptr, acptr, &setflags, 0);
413 diff -r 37c9c7460603 ircd/parse.c
417 { m_ignore, m_ignore, ms_reburst, m_ignore, m_ignore }
422 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
423 + /* UNREG, CLIENT, SERVER, OPER, SERVICE */
424 + { m_ignore, m_ignore, ms_remotemode, m_ignore, m_ignore }
429 0, MAXPARA, MFLG_SLOW, 0, NULL,