]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - remotemode.patch
rename patch files
[irc/quakenet/snircd-patchqueue.git] / remotemode.patch
CommitLineData
6e84167f 1# HG changeset patch
2# Parent 37c9c74606033a6520033f95aa61690a8e4bcadd
3
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
13
14diff -r 37c9c7460603 include/handlers.h
15--- a/include/handlers.h
16+++ b/include/handlers.h
17@@ -225,6 +225,7 @@
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*[]);
25diff -r 37c9c7460603 include/msg.h
26--- a/include/msg.h
27+++ b/include/msg.h
28@@ -368,6 +368,10 @@
29 #define TOK_REBURST "RB"
30 #define CMD_REBURST MSG_REBURST, TOK_REBURST
31
32+#define MSG_REMOTEMODE "REMOTEMODE" /* REMOTEMODE */
33+#define TOK_REMOTEMODE "RM"
34+#define CMD_REMOTEMODE MSG_REMOTEMODE, TOK_REMOTEMODE
35+
36 #define MSG_CAP "CAP"
37 #define TOK_CAP "CAP"
38 #define CMD_CAP MSG_CAP, TOK_CAP
39diff -r 37c9c7460603 ircd/Makefile.in
40--- a/ircd/Makefile.in
41+++ b/ircd/Makefile.in
42@@ -163,6 +163,7 @@
43 m_quit.c \
44 m_reburst.c \
45 m_rehash.c \
46+ m_remotemode.c \
47 m_reset.c \
48 m_restart.c \
49 m_rping.c \
50diff -r 37c9c7460603 ircd/m_remotemode.c
51--- /dev/null
52+++ b/ircd/m_remotemode.c
e7fb5db5 53@@ -0,0 +1,359 @@
6e84167f 54+/*
55+ * IRC - Internet Relay Chat, ircd/m_mode.c
56+ * Copyright (C) 1990 Jarkko Oikarinen and
57+ * University of Oulu, Computing Center
58+ *
59+ * See file AUTHORS in IRC package for additional names of
60+ * the programmers.
61+ *
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.
66+ *
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.
71+ *
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.
75+ *
76+ * $Id: m_mode.c 1818 2007-07-14 02:40:01Z isomer $
77+ */
78+
79+/*
80+ * m_functions execute protocol messages on this server:
81+ *
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...).
87+ *
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.
91+ *
92+ * (!IsServer(cptr)) => (cptr == sptr), because
93+ * prefixes are taken *only* from servers...
94+ *
95+ * (IsServer(cptr))
96+ * (sptr == cptr) => the message didn't
97+ * have the prefix.
98+ *
99+ * (sptr != cptr && IsServer(sptr) means
100+ * the prefix specified servername. (?)
101+ *
102+ * (sptr != cptr && !IsServer(sptr) means
103+ * that message originated from a remote
104+ * user (not local).
105+ *
106+ * combining
107+ *
108+ * (!IsServer(sptr)) means that, sptr can safely
109+ * taken as defining the target structure of the
110+ * message in this server.
111+ *
112+ * *Always* true (if 'parse' and others are working correct):
113+ *
114+ * 1) sptr->from == cptr (note: cptr->from == cptr)
115+ *
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 ]
120+ *
121+ * parc number of variable parameter strings (if zero,
122+ * parv is allowed to be NULL)
123+ *
124+ * parv a NULL terminated list of parameter pointers,
125+ *
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*
131+ *
132+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
133+ * non-NULL pointers.
134+ */
135+
136+#include "config.h"
137+
138+#include "channel.h"
139+#include "client.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"
145+#include "msg.h"
146+#include "msgq.h"
147+#include "numeric.h"
148+#include "querycmds.h"
149+#include "s_conf.h"
150+#include "s_debug.h"
151+#include "s_user.h"
152+#include "send.h"
153+#include "struct.h"
154+#include "numnicks.h"
155+
156+#include <stdlib.h>
157+
158+/**
159+ * ms_remotemode - remotemode server message handler
160+ *
161+ * parv[0] = sender prefix
162+ * parv[1] = target user numeric
163+ * parv[2+] = mode and arguments
164+ *
165+ */
166+int ms_remotemode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
167+{
168+ char *target;
169+ struct Client *acptr;
170+ struct Flags setflags;
171+ struct Membership *chan;
172+
173+ char** p;
174+ char* m;
175+ char *hostmask;
176+ char *user = NULL;
177+ char *host = NULL;
178+ char hiddenhost[USERLEN + HOSTLEN + 2];
179+ int what = MODE_ADD;
180+ int do_host_hiding = 0;
181+ int do_set_host = 0;
182+
183+ /* not from a server */
184+ if (!IsServer(sptr))
185+ return protocol_violation(cptr, "Received REMOTEMODE from user %C", sptr);
186+
187+ /* check paramaters */
188+ if (parc < 3)
189+ return protocol_violation(cptr, "Received too few parameters for REMOTEMODE from %C (got %d - need at least 3)", parc, sptr);
190+
191+ target = parv[1];
192+
193+ /* find user */
194+ if(!(acptr = findNUser(target)))
195+ return 0;
196+
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,
201+ parv[2],
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] : "");
214+ return 0;
215+ }
216+
217+ /* backup flags */
218+ setflags = cli_flags(acptr);
219+
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++) {
223+ switch (*m) {
224+ case '+':
225+ what = MODE_ADD;
226+ break;
227+ case '-':
228+ what = MODE_DEL;
229+ break;
230+ case 'w':
231+ if (what == MODE_ADD)
232+ SetWallops(acptr);
233+ else
234+ ClearWallops(acptr);
235+ break;
236+ case 'i':
237+ if (what == MODE_ADD)
238+ SetInvisible(acptr);
239+ else
240+ ClearInvisible(acptr);
241+ break;
242+ case 'd':
243+ if (what == MODE_ADD)
244+ SetDeaf(acptr);
245+ else
246+ ClearDeaf(acptr);
247+ break;
248+ case 'n':
249+ if (what == MODE_ADD)
250+ SetNoChan(acptr);
251+ else
252+ ClearNoChan(acptr);
253+ break;
254+ case 'I':
255+ if (what == MODE_ADD)
256+ SetNoIdle(acptr);
257+ else
258+ ClearNoIdle(acptr);
259+ break;
260+ case 'R':
261+ if (what == MODE_ADD)
262+ SetAccountOnly(acptr);
263+ else
264+ ClearAccountOnly(acptr);
265+ break;
266+ case 'x':
267+ if (what == MODE_ADD)
268+ do_host_hiding = 1;
269+ break;
270+ case 'h':
271+ if (what == MODE_ADD) {
272+ if (*(p + 1) && is_hostmask(*(p + 1))) {
273+ do_set_host = 1;
274+ hostmask = *++p;
275+ } else {
276+ if (!*(p+1))
277+ protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr);
278+ else {
279+ protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr);
280+ p++; /* Swallow the arg anyway */
281+ }
282+ }
283+ } else { /* MODE_DEL */
284+ do_set_host = 1;
285+ hostmask = NULL;
286+ }
287+ break;
288+
289+ default:
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);
292+ break;
293+ }
294+ }
295+ }
296+
6e84167f 297+ /* do host hiding for +x */
298+ if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
299+ hide_hostmask(acptr, FLAG_HIDDENHOST);
300+
301+ /* sanity checks for -h */
302+ if (do_set_host && !hostmask) {
303+ /* user has no sethost or has no account
304+ *
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
308+ */
309+ if (!IsSetHost(acptr) || !IsAccount(acptr))
310+ do_set_host = 0;
311+
312+ /* user not +x and not allowed to set it */
313+ else if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING))
314+ do_set_host = 0;
315+
316+ /* set +x */
317+ else
318+ SetHiddenHost(acptr);
319+ }
320+
321+ /* sanity checks for +h */
322+ if (do_set_host && hostmask) {
323+ if ((host = strrchr(hostmask, '@'))) {
324+ *host++ = '\0';
325+ user = hostmask;
326+ }
327+ else
328+ host = hostmask;
329+
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)
334+ do_set_host = 0;
335+ }
336+
337+ /* do host hiding for +h/-h */
338+ if (do_set_host) {
339+
340+ /* quit user from channel */
341+ sendcmdto_common_channels_butone(acptr, CMD_QUIT, acptr, ":Host change");
342+
343+ /* set +h */
344+ if (host) {
345+ SetSetHost(acptr);
346+ /* clear +h in old flags so +h is sent out again with new sethost param */
347+ FlagClr(&setflags, FLAG_SETHOST);
348+ if (user)
349+ ircd_strncpy(cli_user(acptr)->username, user, USERLEN);
350+ ircd_strncpy(cli_user(acptr)->host, host, HOSTLEN);
351+
352+ /* set -h */
353+ } else {
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));
360+ else
361+ ircd_strncpy(cli_user(acptr)->host, cli_user(acptr)->realhost, HOSTLEN);
362+ }
363+
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);
368+
369+ /*
370+ * Go through all channels the client was on, rejoin him
371+ * and set the modes, if any
372+ */
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))
377+ continue;
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);
384+ } else {
385+ sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chan->channel, acptr, 0,
386+ "%H", chan->channel);
387+ }
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);
394+ }
395+ }
396+ }
397+
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;
402+ }
403+ if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(acptr)) {
404+ ++UserStats.inv_clients;
405+ }
406+ assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
407+
408+ /* send out the mode */
409+ send_umode_out(acptr, acptr, &setflags, 0);
410+
411+ return 0;
412+}
413diff -r 37c9c7460603 ircd/parse.c
414--- a/ircd/parse.c
415+++ b/ircd/parse.c
416@@ -548,6 +548,13 @@
417 { m_ignore, m_ignore, ms_reburst, m_ignore, m_ignore }
418 },
419 {
420+ MSG_REMOTEMODE,
421+ TOK_REMOTEMODE,
422+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
423+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
424+ { m_ignore, m_ignore, ms_remotemode, m_ignore, m_ignore }
425+ },
426+ {
427 MSG_HASH,
428 TOK_HASH,
429 0, MAXPARA, MFLG_SLOW, 0, NULL,