]>
Commit | Line | Data |
---|---|---|
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 | ||
14 | diff -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*[]); | |
25 | diff -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 | |
39 | diff -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 \ | |
50 | diff -r 37c9c7460603 ircd/m_remotemode.c | |
51 | --- /dev/null | |
52 | +++ b/ircd/m_remotemode.c | |
53 | @@ -0,0 +1,363 @@ | |
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 | + | |
297 | + /* only send wallops to opers */ | |
298 | + if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(acptr) && !FlagHas(&setflags, FLAG_WALLOP)) | |
299 | + ClearWallops(acptr); | |
300 | + | |
301 | + /* do host hiding for +x */ | |
302 | + if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding) | |
303 | + hide_hostmask(acptr, FLAG_HIDDENHOST); | |
304 | + | |
305 | + /* sanity checks for -h */ | |
306 | + if (do_set_host && !hostmask) { | |
307 | + /* user has no sethost or has no account | |
308 | + * | |
309 | + * user has +h - their host is hidden, do not remove it | |
310 | + * unless the user has an account set | |
311 | + * we should not out of the blue expose the real host | |
312 | + */ | |
313 | + if (!IsSetHost(acptr) || !IsAccount(acptr)) | |
314 | + do_set_host = 0; | |
315 | + | |
316 | + /* user not +x and not allowed to set it */ | |
317 | + else if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING)) | |
318 | + do_set_host = 0; | |
319 | + | |
320 | + /* set +x */ | |
321 | + else | |
322 | + SetHiddenHost(acptr); | |
323 | + } | |
324 | + | |
325 | + /* sanity checks for +h */ | |
326 | + if (do_set_host && hostmask) { | |
327 | + if ((host = strrchr(hostmask, '@'))) { | |
328 | + *host++ = '\0'; | |
329 | + user = hostmask; | |
330 | + } | |
331 | + else | |
332 | + host = hostmask; | |
333 | + | |
334 | + /* check if new sethost is different from before */ | |
335 | + if (IsSetHost(acptr) && | |
336 | + (!user || strcmp(cli_user(acptr)->username, user) == 0) && | |
337 | + strcmp(cli_user(acptr)->host, host) == 0) | |
338 | + do_set_host = 0; | |
339 | + } | |
340 | + | |
341 | + /* do host hiding for +h/-h */ | |
342 | + if (do_set_host) { | |
343 | + | |
344 | + /* quit user from channel */ | |
345 | + sendcmdto_common_channels_butone(acptr, CMD_QUIT, acptr, ":Host change"); | |
346 | + | |
347 | + /* set +h */ | |
348 | + if (host) { | |
349 | + SetSetHost(acptr); | |
350 | + /* clear +h in old flags so +h is sent out again with new sethost param */ | |
351 | + FlagClr(&setflags, FLAG_SETHOST); | |
352 | + if (user) | |
353 | + ircd_strncpy(cli_user(acptr)->username, user, USERLEN); | |
354 | + ircd_strncpy(cli_user(acptr)->host, host, HOSTLEN); | |
355 | + | |
356 | + /* set -h */ | |
357 | + } else { | |
358 | + ClearSetHost(acptr); | |
359 | + ircd_strncpy(cli_user(acptr)->username, cli_user(acptr)->realusername, USERLEN); | |
360 | + /* user is +rx - need to restore +x host */ | |
361 | + if (HasHiddenHost(acptr)) | |
362 | + ircd_snprintf(0, cli_user(acptr)->host, HOSTLEN, "%s.%s", | |
363 | + cli_user(acptr)->account, feature_str(FEAT_HIDDEN_HOST)); | |
364 | + else | |
365 | + ircd_strncpy(cli_user(acptr)->host, cli_user(acptr)->realhost, HOSTLEN); | |
366 | + } | |
367 | + | |
368 | + /* inform user of hidden host */ | |
369 | + ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s", | |
370 | + cli_user(acptr)->username, cli_user(acptr)->host); | |
371 | + send_reply(acptr, RPL_HOSTHIDDEN, hiddenhost); | |
372 | + | |
373 | + /* | |
374 | + * Go through all channels the client was on, rejoin him | |
375 | + * and set the modes, if any | |
376 | + */ | |
377 | + for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel) { | |
378 | + /* Invalidate bans against the user so we check them again */ | |
379 | + ClearBanValid(chan); | |
380 | + if (IsZombie(chan)) | |
381 | + continue; | |
382 | + /* If this channel has delayed joins and the user has no modes, just set | |
383 | + * the delayed join flag rather than showing the join, even if the user | |
384 | + * was visible before */ | |
385 | + if (!IsChanOp(chan) && !HasVoice(chan) | |
386 | + && (chan->channel->mode.mode & MODE_DELJOINS)) { | |
387 | + SetDelayedJoin(chan); | |
388 | + } else { | |
389 | + sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chan->channel, acptr, 0, | |
390 | + "%H", chan->channel); | |
391 | + } | |
392 | + if (IsChanOp(chan) && HasVoice(chan)) { | |
393 | + sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, acptr, 0, | |
394 | + "%H +ov %C %C", chan->channel, acptr, acptr); | |
395 | + } else if (IsChanOp(chan) || HasVoice(chan)) { | |
396 | + sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, acptr, 0, | |
397 | + "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', acptr); | |
398 | + } | |
399 | + } | |
400 | + } | |
401 | + | |
402 | + /* adjust count for invisible/visible users */ | |
403 | + if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(acptr)) { | |
404 | + assert(UserStats.inv_clients > 0); | |
405 | + --UserStats.inv_clients; | |
406 | + } | |
407 | + if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(acptr)) { | |
408 | + ++UserStats.inv_clients; | |
409 | + } | |
410 | + assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns); | |
411 | + | |
412 | + /* send out the mode */ | |
413 | + send_umode_out(acptr, acptr, &setflags, 0); | |
414 | + | |
415 | + return 0; | |
416 | +} | |
417 | diff -r 37c9c7460603 ircd/parse.c | |
418 | --- a/ircd/parse.c | |
419 | +++ b/ircd/parse.c | |
420 | @@ -548,6 +548,13 @@ | |
421 | { m_ignore, m_ignore, ms_reburst, m_ignore, m_ignore } | |
422 | }, | |
423 | { | |
424 | + MSG_REMOTEMODE, | |
425 | + TOK_REMOTEMODE, | |
426 | + 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
427 | + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
428 | + { m_ignore, m_ignore, ms_remotemode, m_ignore, m_ignore } | |
429 | + }, | |
430 | + { | |
431 | MSG_HASH, | |
432 | TOK_HASH, | |
433 | 0, MAXPARA, MFLG_SLOW, 0, NULL, |