2 * IRC - Internet Relay Chat, ircd/m_gline.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
88 #include "ircd_features.h"
90 #include "ircd_reply.h"
91 #include "ircd_string.h"
100 /* #include <assert.h> -- Now using assert in ircd_log.h */
105 * ms_gline - server message handler
107 * parv[0] = Sender prefix
108 * parv[1] = Target: server numeric
109 * parv[2] = (+|-)<G-line mask>
110 * parv[3] = G-line lifetime
116 * From somewhere else:
118 * parv[4] = Last modification time
123 ms_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
125 struct Client *acptr = 0;
126 struct Gline *agline = 0;
127 unsigned int flags = 0;
128 enum GlineAction action = GLINE_MODIFY;
129 time_t expire_off = 0, lastmod = 0, lifetime = 0;
130 char *mask = parv[2], *target = parv[1], *reason = "No reason", *tmp = 0;
133 return need_more_params(sptr, "GLINE");
137 flags |= GLINE_OPERFORCE; /* assume oper had WIDE_GLINE */
138 } else if (IsServer(sptr))
139 flags |= GLINE_FORCE;
141 switch (*mask) { /* handle +, -, <, and > */
142 case '+': /* activate the G-line */
143 action = GLINE_ACTIVATE;
147 case '-': /* deactivate the G-line */
148 action = GLINE_DEACTIVATE;
152 case '>': /* locally activate the G-line */
153 action = GLINE_LOCAL_ACTIVATE;
157 case '<': /* locally deactivate the G-line */
158 action = GLINE_LOCAL_DEACTIVATE;
163 /* Now, let's figure out if it's a local or global G-line */
164 if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE ||
165 (target[0] == '*' && target[1] == '\0'))
166 flags |= GLINE_GLOBAL;
168 if (!(acptr = FindNServer(target)))
169 return 0; /* no such server, jump out */
171 flags |= GLINE_LOCAL;
174 /* Next, try to find the G-line... */
175 if ((flags & GLINE_GLOBAL) || IsMe(acptr)) /* don't bother if it's not me! */
176 agline = gline_find(mask, flags | GLINE_ANY | GLINE_EXACT);
178 /* We now have all the pieces to tell us what we've got; let's
179 * put it all together and convert the rest of the arguments.
182 /* Handle the local G-lines first... */
183 if (flags & GLINE_LOCAL) {
186 /* normalize the action, first */
187 if (action == GLINE_LOCAL_ACTIVATE || action == GLINE_MODIFY)
188 action = GLINE_ACTIVATE;
189 else if (action == GLINE_LOCAL_DEACTIVATE)
190 action = GLINE_DEACTIVATE;
192 if (action == GLINE_ACTIVATE) { /* get expiration and reason */
193 if (parc < 5) /* check parameter count... */
194 return need_more_params(sptr, "GLINE");
196 expire_off = atoi(parv[3]); /* get expiration... */
197 reason = parv[parc - 1]; /* and reason */
200 /* XXX and create the local G-line */
201 sendwallto_group_butone(&me, WALL_DESYNCH, NULL,
202 "I would create a local G-line here; target "
203 "%s, mask %s, operforce %s, action %s, "
204 "expire %Tu, reason: %s", target, mask,
205 flags & GLINE_OPERFORCE ? "YES" : "NO",
206 action == GLINE_ACTIVATE ? "+" : "-",
209 } else if (IsMe(acptr)) { /* destroying a local G-line */
210 /* XXX destroy the G-line */;
211 sendwallto_group_butone(&me, WALL_DESYNCH, NULL,
212 "I would destroy a local G-line here; target "
213 "%s, mask %s, operforce %s, action %s", target,
214 mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
215 action == GLINE_ACTIVATE ? "+" : "-");
218 /* OK, we've converted arguments; if it's not for us, forward */
219 /* UPDATE NOTE: Once all servers are updated to u2.10.12.11, the
220 * format string in this sendcmdto_one() may be updated to omit
221 * <lastmod> for GLINE_ACTIVATE and to omit <expire>, <lastmod>,
222 * and <reason> for GLINE_DEACTIVATE.
225 sendwallto_group_butone(&me, WALL_DESYNCH, NULL,
226 "I am forwarding a local G-line to a remote "
227 "server; target %s, mask %s, operforce %s, "
228 "action %s, expire %Tu, lastmod %Tu, reason: %s",
230 flags & GLINE_OPERFORCE ? "YES" : "NO",
231 action == GLINE_ACTIVATE ? "+" : "-",
232 expire_off, CurrentTime, reason);
233 sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
234 acptr, flags & GLINE_OPERFORCE ? "!" : "",
235 action == GLINE_ACTIVATE ? '+' : '-', mask, expire_off,
236 CurrentTime, reason);
239 return 0; /* all done */
242 /* can't modify a G-line that doesn't exist, so remap to activate */
243 if (!agline && action == GLINE_MODIFY)
244 action = GLINE_ACTIVATE;
246 /* OK, let's figure out what other parameters we may have... */
248 case GLINE_LOCAL_ACTIVATE: /* locally activating a G-line */
249 case GLINE_LOCAL_DEACTIVATE: /* locally deactivating a G-line */
250 break; /* no additional parameters to manipulate */
252 case GLINE_ACTIVATE: /* activating a G-line */
253 case GLINE_DEACTIVATE: /* deactivating a G-line */
254 /* in either of these cases, we have at least a lastmod parameter */
256 return need_more_params(sptr, "GLINE");
257 else if (parc == 4) /* lastmod only form... */
258 lastmod = atoi(parv[3]);
260 case GLINE_MODIFY: /* modifying a G-line */
261 /* convert expire and lastmod, look for lifetime and reason */
262 if (parc > 4) { /* protect against fall-through from 4-param form */
264 return need_more_params(sptr, "GLINE");
266 expire_off = atoi(parv[3]); /* convert expiration and lastmod */
267 lastmod = atoi(parv[4]);
269 if (parc > 6) { /* no question, have a lifetime and reason */
270 lifetime = atoi(parv[5]);
271 reason = parv[parc - 1];
272 } else if (parc == 6) { /* either a lifetime or a reason */
273 if (!agline || /* gline creation, has to be the reason */
274 /* trial-convert as lifetime, and if it doesn't fully convert,
275 * it must be the reason */
276 ((lifetime = strtoul(parv[5], &tmp, 10)) && !*tmp)) {
284 sendwallto_group_butone(&me, WALL_DESYNCH, NULL,
285 "I have a global G-line I would act upon now; "
286 "target %s, mask %s, operforce %s, action %s, "
287 "expire %Tu, lastmod %Tu, lifetime %Tu, "
288 "reason: %s; gline %s!",
289 target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
290 action == GLINE_ACTIVATE ? "+" :
291 (action == GLINE_DEACTIVATE ? "-" :
292 (action == GLINE_LOCAL_ACTIVATE ? ">" :
293 (action == GLINE_LOCAL_DEACTIVATE ? "<" :
294 "(MODIFY)"))), expire_off, lastmod, lifetime,
295 reason, agline ? "EXISTS" : "does not exist");
297 /* OK, at this point, we have converted all available parameters.
298 * Let's actually do the action!
301 /* XXX modify the G-line */;
303 /* XXX create the G-line */return 0;
309 /* if ((parc == 3 && *mask == '-') || parc == 5) */
311 /* if (!find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) */
312 /* return need_more_params(sptr, "GLINE"); */
314 /* flags |= GLINE_FORCE; */
316 /* else if (parc > 5) */
317 /* lastmod = atoi(parv[4]); */
319 /* return need_more_params(sptr, "GLINE"); */
322 /* reason = parv[parc - 1]; */
324 /* if (IsServer(sptr)) */
325 /* flags |= GLINE_FORCE; */
327 /* if (!(target[0] == '*' && target[1] == '\0')) { */
328 /* if (!(acptr = FindNServer(target))) */
329 /* return 0; /\* no such server *\/ */
331 /* if (!IsMe(acptr)) { /\* manually propagate *\/ */
333 /* sendcmdto_one(sptr, CMD_GLINE, acptr, */
334 /* (parc == 3) ? "%C %s" : "%C %s %s :%s", acptr, mask, */
335 /* parv[3], reason); */
337 /* sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%s %s %s :%s", acptr, */
338 /* flags & GLINE_OPERFORCE ? "!" : "", mask, parv[3], */
339 /* parv[4], reason); */
344 /* flags |= GLINE_LOCAL; */
347 /* if (*mask == '-') */
349 /* else if (*mask == '+') { */
350 /* flags |= GLINE_ACTIVE; */
353 /* flags |= GLINE_ACTIVE; */
355 /* expire_off = parc < 5 ? 0 : atoi(parv[3]); */
357 /* agline = gline_find(mask, GLINE_ANY | GLINE_EXACT); */
360 /* if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /\* global over local *\/ */
361 /* gline_free(agline); */
362 /* else if (!lastmod && ((flags & GLINE_ACTIVE) == GlineIsRemActive(agline))) */
363 /* return gline_propagate(cptr, sptr, agline); */
364 /* else if (!lastmod || GlineLastMod(agline) < lastmod) { /\* new mod *\/ */
365 /* if (flags & GLINE_ACTIVE) */
366 /* return gline_activate(cptr, sptr, agline, lastmod, flags); */
368 /* return gline_deactivate(cptr, sptr, agline, lastmod, flags); */
369 /* } else if (GlineLastMod(agline) == lastmod || IsBurstOrBurstAck(cptr)) */
372 /* return gline_resend(cptr, agline); /\* other server desynched WRT gline *\/ */
373 /* } else if (parc == 3 && !(flags & GLINE_ACTIVE)) { */
374 /* /\* U-lined server removing a G-line we don't have; propagate the removal */
377 /* if (!(flags & GLINE_LOCAL)) */
378 /* sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* -%s", mask); */
380 /* } else if (parc < 5) */
381 /* return need_more_params(sptr, "GLINE"); */
383 /* return gline_add(cptr, sptr, mask, reason, expire_off, lastmod, flags); */
387 * mo_gline - oper message handler
389 * parv[0] = Sender prefix
390 * parv[1] = [[+|-]<G-line mask>]
392 * Local (to me) style:
394 * parv[2] = [Expiration offset]
395 * parv[3] = [Comment]
397 * Global (or remote local) style:
400 * parv[3] = [Expiration offset]
401 * parv[4] = [Comment]
405 mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
407 struct Client *acptr = 0;
408 struct Gline *agline;
409 unsigned int flags = 0;
411 char *mask = parv[1], *target = 0, *reason;
414 return gline_list(sptr, 0);
419 if (HasPriv(sptr, PRIV_WIDE_GLINE))
420 flags |= GLINE_OPERFORCE;
424 flags |= GLINE_ACTIVE;
427 } else if (*mask == '-')
430 return gline_list(sptr, mask);
433 expire_off = atoi(parv[2]);
435 flags |= GLINE_LOCAL;
436 } else if (parc > 4) {
438 expire_off = atoi(parv[3]);
441 return need_more_params(sptr, "GLINE");
445 if (!(target[0] == '*' && target[1] == '\0'))
447 if (!(acptr = find_match_server(target)))
448 return send_reply(sptr, ERR_NOSUCHSERVER, target);
450 /* manually propagate, since we don't set it */
453 if (!feature_bool(FEAT_CONFIG_OPERCMDS))
454 return send_reply(sptr, ERR_DISABLED, "GLINE");
456 if (!HasPriv(sptr, PRIV_GLINE))
457 return send_reply(sptr, ERR_NOPRIVILEGES);
459 sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %s %Tu :%s", acptr,
460 flags & GLINE_OPERFORCE ? "!" : "",
461 flags & GLINE_ACTIVE ? '+' : '-', mask, parv[3],
465 flags |= GLINE_LOCAL;
469 if (!(flags & GLINE_LOCAL) && !feature_bool(FEAT_CONFIG_OPERCMDS))
470 return send_reply(sptr, ERR_DISABLED, "GLINE");
472 if (!HasPriv(sptr, (flags & GLINE_LOCAL ? PRIV_LOCAL_GLINE : PRIV_GLINE)))
473 return send_reply(sptr, ERR_NOPRIVILEGES);
475 agline = gline_find(mask, GLINE_ANY | GLINE_EXACT);
478 if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */
481 if (!GlineLastMod(agline)) /* force mods to Uworld-set G-lines local */
482 flags |= GLINE_LOCAL;
484 if (flags & GLINE_ACTIVE)
485 return gline_activate(cptr, sptr, agline,
486 GlineLastMod(agline) ? TStime() : 0, flags);
488 return gline_deactivate(cptr, sptr, agline,
489 GlineLastMod(agline) ? TStime() : 0, flags);
493 return gline_add(cptr, sptr, mask, reason, expire_off, TStime(), flags);
497 * m_gline - user message handler
499 * parv[0] = Sender prefix
500 * parv[1] = [<server name>]
504 m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
507 return send_reply(sptr, ERR_NOSUCHGLINE, "");
509 return gline_list(sptr, parv[1]);