ircu2.10.12 pk910 fork
[ircu2.10.12-pk.git] / ircd / jupe.c
1 /*
2  * IRC - Internet Relay Chat, ircd/jupe.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Finland
5  * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 1, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 /** @file
22  * @brief Implementation of juped server handling functions.
23  * @version $Id: jupe.c 1633 2006-03-25 03:46:56Z entrope $
24  */
25 #include "config.h"
26
27 #include "jupe.h"
28 #include "client.h"
29 #include "hash.h"
30 #include "ircd.h"
31 #include "ircd_alloc.h"
32 #include "ircd_features.h"
33 #include "ircd_log.h"
34 #include "ircd_reply.h"
35 #include "ircd_string.h"
36 #include "match.h"
37 #include "msg.h"
38 #include "numeric.h"
39 #include "numnicks.h"
40 #include "s_bsd.h"
41 #include "s_misc.h"
42 #include "send.h"
43 #include "struct.h"
44 #include "sys.h"    /* FALSE bleah */
45
46 /* #include <assert.h> -- Now using assert in ircd_log.h */
47 #include <string.h>
48
49 /** List of jupes. */
50 static struct Jupe *GlobalJupeList = 0;
51
52 /** Allocate a new jupe with the given parameters.
53  * @param[in] server Server name to jupe.
54  * @param[in] reason Reason for jupe.
55  * @param[in] expire Expiration time for jupe.
56  * @param[in] lastmod Last modification time for jupe.
57  * @param[in] flags Flags to set for the jupe.
58  */
59 static struct Jupe *
60 make_jupe(char *server, char *reason, time_t expire, time_t lastmod,
61           unsigned int flags)
62 {
63   struct Jupe *ajupe;
64
65   ajupe = (struct Jupe*) MyMalloc(sizeof(struct Jupe)); /* alloc memory */
66   assert(0 != ajupe);
67
68   memset(ajupe, 0, sizeof(*ajupe));
69   DupString(ajupe->ju_server, server); /* copy vital information */
70   DupString(ajupe->ju_reason, reason);
71   ajupe->ju_expire = expire;
72   ajupe->ju_lastmod = lastmod;
73   ajupe->ju_flags = flags & JUPE_MASK; /* set jupe flags */
74
75   ajupe->ju_next = GlobalJupeList; /* link it into the list */
76   ajupe->ju_prev_p = &GlobalJupeList;
77   if (GlobalJupeList)
78     GlobalJupeList->ju_prev_p = &ajupe->ju_next;
79   GlobalJupeList = ajupe;
80
81   return ajupe;
82 }
83
84 /** Apply a jupe.
85  * @param[in] cptr Local client that sent us the jupe.
86  * @param[in] sptr Originator of the jupe.
87  * @param[in] jupe Jupe to check.
88  */
89 static int
90 do_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
91 {
92   struct Client *acptr;
93
94   if (!JupeIsActive(jupe)) /* no action to be taken on inactive jupes */
95     return 0;
96
97   acptr = FindServer(jupe->ju_server);
98
99   /* server isn't online or isn't local or is me */
100   if (!acptr || !MyConnect(acptr) || IsMe(acptr))
101     return 0;
102
103   return exit_client_msg(cptr, acptr, &me, "Juped: %s", jupe->ju_reason);
104 }
105
106 /** Forward a jupe to another server.
107  * @param[in] cptr Local client that sent us the jupe.
108  * @param[in] sptr Originator of the jupe.
109  * @param[in] jupe Jupe to forward.
110  */
111 static void
112 propagate_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
113 {
114   if (JupeIsLocal(jupe)) /* don't propagate local jupes */
115     return;
116
117   sendcmdto_serv_butone(sptr, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
118                         JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
119                         jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
120                         jupe->ju_reason);
121 }
122
123 /** Add a new server jupe.
124  * @param[in] cptr Local client that sent us the jupe.
125  * @param[in] sptr Originator of the jupe.
126  * @param[in] server Server name to jupe.
127  * @param[in] reason Reason for the jupe.
128  * @param[in] expire Jupe duration in seconds.
129  * @param[in] lastmod Last modification timestamp (or NULL).
130  * @param[in] flags Flags to set on jupe.
131  * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
132  * case CPTR_KILLED.
133  */
134 int
135 jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason,
136          time_t expire, time_t lastmod, unsigned int flags)
137 {
138   struct Jupe *ajupe;
139
140   assert(0 != server);
141   assert(0 != reason);
142
143   /*
144    * You cannot set a negative (or zero) expire time, nor can you set an
145    * expiration time for greater than JUPE_MAX_EXPIRE.
146    */
147   if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
148     if (!IsServer(cptr) && MyConnect(cptr))
149       send_reply(cptr, ERR_BADEXPIRE, expire);
150     return 0;
151   }
152
153   expire += CurrentTime; /* convert from lifetime to timestamp */
154
155   /* Inform ops and log it */
156   sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
157                        "%Tu: %s",
158                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
159                          cli_name(sptr) :
160                          cli_name((cli_user(sptr))->server),
161                        flags & JUPE_LOCAL ? "local " : "", server,
162                        expire + TSoffset, reason);
163
164   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
165             "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr,
166             flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset,
167             reason);
168
169   /* make the jupe */
170   ajupe = make_jupe(server, reason, expire, lastmod, flags);
171
172   propagate_jupe(cptr, sptr, ajupe);
173
174   return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
175 }
176
177 /** Activate a jupe, optionally changing its lastmod and flags.
178  * @param[in] cptr Local client that sent us the jupe.
179  * @param[in] sptr Originator of the jupe.
180  * @param[in] jupe Jupe to activate.
181  * @param[in] lastmod New timestamp for last modification of the jupe.
182  * @param[in] flags Flags to set on the jupe.
183  * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
184  * case CPTR_KILLED.
185  */
186 int
187 jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
188               time_t lastmod, unsigned int flags)
189 {
190   unsigned int saveflags = 0;
191
192   assert(0 != jupe);
193
194   saveflags = jupe->ju_flags;
195
196   if (flags & JUPE_LOCAL)
197     jupe->ju_flags &= ~JUPE_LDEACT;
198   else {
199     jupe->ju_flags |= JUPE_ACTIVE;
200
201     if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
202       jupe->ju_lastmod++;
203     else
204       jupe->ju_lastmod = lastmod;
205   }
206
207   if ((saveflags & JUPE_ACTMASK) == JUPE_ACTIVE)
208     return 0; /* was active to begin with */
209
210   /* Inform ops and log it */
211   sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring "
212                        "at %Tu: %s",
213                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
214                          cli_name(sptr) :
215                          cli_name((cli_user(sptr))->server),
216                        jupe->ju_server, jupe->ju_expire + TSoffset,
217                        jupe->ju_reason);
218
219   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
220             "%#C activating JUPE for %s, expiring at %Tu: %s",sptr,
221             jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
222
223   if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
224     propagate_jupe(cptr, sptr, jupe);
225
226   return do_jupe(cptr, sptr, jupe);
227 }
228
229 /** Deactivate a jupe.
230  * @param[in] cptr Local client that sent us the jupe.
231  * @param[in] sptr Originator of the jupe.
232  * @param[in] jupe Jupe to deactivate.
233  * @param[in] lastmod New timestamp for last modification of the jupe.
234  * @param[in] flags Flags to set on the jupe.
235  * @return Zero.
236  */
237 int
238 jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
239                 time_t lastmod, unsigned int flags)
240 {
241   unsigned int saveflags = 0;
242
243   assert(0 != jupe);
244
245   saveflags = jupe->ju_flags;
246
247   if (!JupeIsLocal(jupe)) {
248     if (flags & JUPE_LOCAL)
249       jupe->ju_flags |= JUPE_LDEACT;
250     else {
251       jupe->ju_flags &= ~JUPE_ACTIVE;
252
253       if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
254         jupe->ju_lastmod++;
255       else
256         jupe->ju_lastmod = lastmod;
257     }
258
259     if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE)
260       return 0; /* was inactive to begin with */
261   }
262
263   /* Inform ops and log it */
264   sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: "
265                        "%s",
266                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
267                          cli_name(sptr) :
268                          cli_name((cli_user(sptr))->server),
269                        JupeIsLocal(jupe) ? "removing local" : "deactivating",
270                        jupe->ju_server, jupe->ju_expire + TSoffset,
271                        jupe->ju_reason);
272
273   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
274             "%#C %s JUPE for %s, expiring at %Tu: %s", sptr,
275             JupeIsLocal(jupe) ? "removing local" : "deactivating",
276             jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
277
278   if (JupeIsLocal(jupe))
279     jupe_free(jupe);
280   else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
281     propagate_jupe(cptr, sptr, jupe);
282
283   return 0;
284 }
285
286 /** Find a jupe by name.
287  * @param[in] server %Jupe name to search for.
288  * @return Matching jupe (or NULL if none match).
289  */
290 struct Jupe *
291 jupe_find(char *server)
292 {
293   struct Jupe* jupe;
294   struct Jupe* sjupe;
295
296   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
297     sjupe = jupe->ju_next;
298
299     if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
300       jupe_free(jupe);
301     else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
302       return jupe;
303   }
304
305   return 0;
306 }
307
308 /** Unlink and free an unused jupe.
309  * @param[in] jupe Server jupe to free.
310  */
311 void
312 jupe_free(struct Jupe* jupe)
313 {
314   assert(0 != jupe);
315
316   *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
317   if (jupe->ju_next)
318     jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
319
320   MyFree(jupe->ju_server);  /* and free up the memory */
321   MyFree(jupe->ju_reason);
322   MyFree(jupe);
323 }
324
325 /** Send the full list of active global jupes to \a cptr.
326  * @param[in] cptr Local server to send jupes to.
327  */
328 void
329 jupe_burst(struct Client *cptr)
330 {
331   struct Jupe *jupe;
332   struct Jupe *sjupe;
333
334   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
335     sjupe = jupe->ju_next;
336
337     if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
338       jupe_free(jupe);
339     else if (!JupeIsLocal(jupe)) /* forward global jupes */
340       sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
341                     JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
342                     jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
343                     jupe->ju_reason);
344   }
345 }
346
347 /** Forward a jupe to another server.
348  * @param[in] cptr %Server to send jupe to.
349  * @param[in] jupe Jupe to forward.
350  */
351 int
352 jupe_resend(struct Client *cptr, struct Jupe *jupe)
353 {
354   if (JupeIsLocal(jupe)) /* don't propagate local jupes */
355     return 0;
356
357   sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
358                 JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
359                 jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
360                 jupe->ju_reason);
361
362   return 0;
363 }
364
365 /** Send a jupe (or a list of jupes) to a server.
366  * @param[in] sptr Client searching for jupes.
367  * @param[in] server Name of jupe to search for (if NULL, list all).
368  * @return Zero.
369  */
370 int
371 jupe_list(struct Client *sptr, char *server)
372 {
373   struct Jupe *jupe;
374   struct Jupe *sjupe;
375
376   if (server) {
377     if (!(jupe = jupe_find(server))) /* no such jupe */
378       return send_reply(sptr, ERR_NOSUCHJUPE, server);
379
380     /* send jupe information along */
381     send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset,
382                JupeIsLocal(jupe) ? cli_name(&me) : "*",
383                JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
384   } else {
385     for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
386       sjupe = jupe->ju_next;
387
388       if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
389         jupe_free(jupe);
390       else /* send jupe information along */
391         send_reply(sptr, RPL_JUPELIST, jupe->ju_server,
392                    jupe->ju_expire + TSoffset,
393                    JupeIsLocal(jupe) ? cli_name(&me) : "*",
394                    JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
395     }
396   }
397
398   /* end of jupe information */
399   return send_reply(sptr, RPL_ENDOFJUPELIST);
400 }
401
402 /** Count jupes and memory used by them.
403  * @param[out] ju_size Receives total number of bytes allocated for jupes.
404  * @return Number of jupes currently allocated.
405  */
406 int
407 jupe_memory_count(size_t *ju_size)
408 {
409   struct Jupe *jupe;
410   unsigned int ju = 0;
411
412   for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next)
413   {
414     ju++;
415     *ju_size += sizeof(struct Jupe);
416     *ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0;
417     *ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0;
418   }
419   return ju;
420 }