ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/contrib/m_operspy.c
Revision: 496
Committed: Wed Mar 1 18:57:10 2006 UTC (20 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 16927 byte(s)
Log Message:
- Fixed bug where "OPERSPY NAMES #channel" would add a
  client twice onto a channel's member list if it is
  already on that channel.

File Contents

# User Rev Content
1 adx 30 /************************************************************************
2     * IRC - Internet Relay Chat, contrib/m_operspy.c
3     * Copyright (C) 2002 William Bierman III and the Hybrid Development Team
4     *
5     * This program is free software; you can redistribute it and/or modify
6     * it under the terms of the GNU General Public License as published by
7     * the Free Software Foundation; either version 1, or (at your option)
8     * any later version.
9     *
10     * This program is distributed in the hope that it will be useful,
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     * GNU General Public License for more details.
14     *
15     * You should have received a copy of the GNU General Public License
16     * along with this program; if not, write to the Free Software
17     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18     *
19 knight 31 * $Id$
20 adx 30 */
21    
22     /*** PLEASE READ ME ***/
23     /*
24     * This module gives an extraordinary amount of power to the opers
25     * who have the access to use it. It allows for users' privacy to
26     * be pretty much obliterated. The Hybrid Team assumes absolutely
27     * no responsibility for this file's (mis)use.
28     *
29     * - billy-jon
30     */
31    
32     #include "stdinc.h"
33     #include "handlers.h"
34     #include "channel.h"
35     #include "channel_mode.h"
36     #include "client.h"
37     #include "common.h" /* FALSE bleah */
38     #include "ircd.h"
39     #include "numeric.h"
40     #include "s_conf.h"
41     #include "s_serv.h"
42     #include "send.h"
43     #include "msg.h"
44     #include "parse.h"
45     #include "modules.h"
46     #include "hash.h"
47    
48     /* enable logging of OPERSPY functions */
49     #define OPERSPY_LOG
50    
51     /* enable this to log all local/remote operspy usage to a logfile */
52     #define OPERSPY_LOGFILE
53    
54     /* enable this to send incoming operspy usage to connected +y (UMODE_SPY) opers */
55     #define OPERSPY_NOTICE
56    
57     /* enable OPERSPY version of LIST */
58     #define OPERSPY_LIST
59    
60     /* enable OPERSPY version of MODE */
61     #define OPERSPY_MODE
62    
63     /* enable OPERSPY version of NAMES */
64     #define OPERSPY_NAMES
65    
66     /* enable OPERSPY version of WHO */
67     #define OPERSPY_WHO
68    
69     /* enable OPERSPY version of WHOIS */
70     #define OPERSPY_WHOIS
71    
72     /* enable OPERSPY version of TOPIC */
73     #define OPERSPY_TOPIC
74    
75     #define IsOperspy(x) (IsOper(x) && MyClient(x) && IsAdmin(x))
76    
77     /* The commands we will add */
78     static void ms_operspy(struct Client *, struct Client *, int, char *[]);
79     static void mo_operspy(struct Client *, struct Client *, int, char *[]);
80    
81     /* extensions for OPERSPY WHO */
82     static void do_who(struct Client *, struct Client *, char *, const char *);
83     static void who_global(struct Client *, char *, int);
84     static void do_who_on_channel(struct Client *, struct Channel *, char *);
85    
86     static void operspy_list(struct Client *, int, char *[]);
87     static void operspy_mode(struct Client *, int, char *[]);
88     static void operspy_names(struct Client *, int, char *[]);
89     static void operspy_topic(struct Client *, int, char *[]);
90     static void operspy_who(struct Client *, int, char *[]);
91     static void operspy_whois(struct Client *, int, char *[]);
92    
93    
94     struct Message operspy_msgtab = {
95     "OPERSPY", 0, 0, 3, 4, MFLG_SLOW, 0,
96 michael 496 { m_ignore, m_not_oper, ms_operspy, ms_operspy, mo_operspy, m_ignore }
97 adx 30 };
98    
99     static const struct operspy_s {
100     const char *const cmd;
101     void (*const func_p)(struct Client *, int, char *[]);
102     } operspy_table[] = {
103     #ifdef OPERSPY_LIST
104     { "LIST", operspy_list },
105     #endif
106     #ifdef OPERSPY_MODE
107     { "MODE", operspy_mode },
108     #endif
109     #ifdef OPERSPY_NAMES
110     { "NAMES", operspy_names },
111     #endif
112     #ifdef OPERSPY_TOPIC
113     { "TOPIC", operspy_topic },
114     #endif
115     #ifdef OPERSPY_WHO
116     { "WHO", operspy_who },
117     #endif
118     #ifdef OPERSPY_WHOIS
119     { "WHOIS", operspy_whois },
120     #endif
121     { NULL, NULL }
122     };
123    
124 adx 443 INIT_MODULE(m_operspy, "$Revision$")
125 adx 30 {
126     mod_add_cmd(&operspy_msgtab);
127     }
128    
129 adx 443 CLEANUP_MODULE
130 adx 30 {
131     mod_del_cmd(&operspy_msgtab);
132     }
133    
134     #ifdef OPERSPY_LOG
135     static void operspy_log(struct Client *, const char *, const char *);
136     #endif
137    
138     static void
139     ms_operspy(struct Client *client_p, struct Client *source_p,
140     int parc, char *parv[])
141     {
142     #ifdef OPERSPY_LOG
143     operspy_log(source_p, parv[1], parv[2]);
144     #endif
145     }
146    
147     /* mo_operspy()
148     * parv[1] = operspy command
149     * parv[2] = command parameter
150     */
151     static void
152     mo_operspy(struct Client *client_p, struct Client *source_p,
153     int parc, char *parv[])
154     {
155     char cmdbuf[IRCD_BUFSIZE] = "<NONE>"; /* in case everything is undef'd */
156     size_t bcnt = 0;
157     const struct operspy_s *optr = NULL;
158    
159     if (!IsOperspy(client_p))
160     {
161     sendto_one(client_p, form_str(ERR_NOPRIVILEGES),
162     me.name, client_p->name);
163     return;
164     }
165    
166     assert(client_p == source_p);
167    
168     for (optr = operspy_table; optr->cmd; ++optr)
169     {
170     if (!irccmp(optr->cmd, parv[1]))
171     {
172     (*optr->func_p)(client_p, parc, parv);
173     return;
174     }
175     }
176    
177     for (optr = operspy_table; optr->cmd; ++optr)
178     {
179     /* str*cat is slow and sucks */
180     bcnt += strlcpy(cmdbuf+bcnt, optr->cmd, sizeof(cmdbuf)-bcnt);
181     if ((optr + 1)->cmd != NULL && bcnt < (sizeof(cmdbuf)-2))
182     {
183     cmdbuf[bcnt++] = ',';
184     cmdbuf[bcnt++] = ' ';
185     }
186     }
187    
188     sendto_one(client_p, ":%s NOTICE %s :%s is not a valid option. Choose from %s",
189     me.name, client_p->name, parv[1], cmdbuf);
190     }
191    
192     static void
193     operspy_list(struct Client *client_p, int parc, char *parv[])
194     {
195     const dlink_node *ptr = NULL;
196     #ifdef OPERSPY_LOG
197     operspy_log(client_p, "LIST", parv[2]);
198     #endif
199    
200     if (*parv[2] == '\0')
201     return;
202    
203     sendto_one(client_p, form_str(RPL_LISTSTART),
204     me.name, client_p->name);
205    
206     DLINK_FOREACH(ptr, global_channel_list.head)
207     {
208     const struct Channel *chptr_list = ptr->data;
209    
210     if (match_chan(parv[2], chptr_list->chname))
211     {
212     sendto_one(client_p, form_str(RPL_LIST), me.name, client_p->name,
213     chptr_list->chname, dlink_list_length(&chptr_list->members),
214     chptr_list->topic == NULL ? "" : chptr_list->topic);
215     }
216     }
217    
218     sendto_one(client_p, form_str(RPL_LISTEND),
219     me.name, client_p->name);
220     }
221    
222     static void
223     operspy_mode(struct Client *client_p, int parc, char *parv[])
224     {
225     /* needed to preserve actual client status */
226     int c_status = 0;
227     char modebuf[MODEBUFLEN];
228     char parabuf[MODEBUFLEN];
229     struct Channel *chptr_mode = NULL;
230    
231     if ((chptr_mode = hash_find_channel(parv[2])) == NULL)
232     {
233     sendto_one(client_p, form_str(ERR_NOSUCHCHANNEL),
234     me.name, client_p->name, parv[2]);
235     return;
236     }
237    
238     #ifdef OPERSPY_LOG
239     operspy_log(client_p, "MODE", parv[2]);
240     #endif
241    
242     /*
243     * XXX - this is a dirty nasty kludge to trick channel_modes()
244     * into giving us the key
245     */
246     c_status = client_p->status;
247     client_p->status = STAT_SERVER;
248    
249     channel_modes(chptr_mode, client_p, modebuf, parabuf);
250     client_p->status = c_status;
251    
252 michael 496 sendto_one(client_p, form_str(RPL_CHANNELMODEIS), me.name,
253     client_p->name, parv[2], modebuf, parabuf);
254     sendto_one(client_p, form_str(RPL_CREATIONTIME), me.name,
255     client_p->name, parv[2], chptr_mode->channelts);
256 adx 30 }
257    
258     static void
259     operspy_names(struct Client *client_p, int parc, char *parv[])
260     {
261     /* as with mode, must preserve channel modes */
262     struct Channel *chptr_names = NULL;
263    
264     if ((chptr_names = hash_find_channel(parv[2])) == NULL)
265     {
266     sendto_one(client_p, form_str(ERR_NOSUCHCHANNEL),
267     me.name, client_p->name, parv[2]);
268     return;
269     }
270    
271     #ifdef OPERSPY_LOG
272     operspy_log(client_p, "NAMES", parv[2]);
273     #endif
274    
275 michael 496 /*
276     * the way to go with this, rather than temporarily setting -sp,
277 adx 30 * is to temporarily add our client to the member list. then
278     * we can also list +i users. an unfortunate side-effect of this
279     * is that your nickname shows up in the list. for now, there is
280     * no easy way around it.
281 michael 496 */
282     if (IsMember(client_p, chptr))
283     channel_member_names(client_p, chptr_names, 1);
284     else {
285     add_user_to_channel(chptr_names, client_p, CHFL_CHANOP, NO);
286     channel_member_names(client_p, chptr_names, 1);
287     remove_user_from_channel(find_channel_link(client_p, chptr_names));
288     }
289 adx 30 }
290    
291     static void
292     operspy_topic(struct Client *client_p, int parc, char *parv[])
293     {
294     const struct Channel *chptr_topic = NULL;
295    
296     if ((chptr_topic = hash_find_channel(parv[2])) == NULL)
297     {
298     sendto_one(client_p, form_str(ERR_NOSUCHCHANNEL),
299     me.name, client_p->name, parv[2]);
300     return;
301     }
302    
303     #ifdef OPERSPY_LOG
304     operspy_log(client_p, "TOPIC", parv[2]);
305     #endif
306    
307     if (chptr_topic->topic == NULL)
308     sendto_one(client_p, form_str(RPL_NOTOPIC),
309     me.name, client_p->name, parv[2]);
310     else
311     {
312     sendto_one(client_p, form_str(RPL_TOPIC), me.name, client_p->name,
313     chptr_topic->chname, chptr_topic->topic);
314     sendto_one(client_p, form_str(RPL_TOPICWHOTIME), me.name,
315     client_p->name, chptr_topic->chname, chptr_topic->topic_info,
316     chptr_topic->topic_time);
317     }
318     }
319    
320     static void
321     operspy_who(struct Client *client_p, int parc, char *parv[])
322     {
323     char *mask = parc > 2 ? parv[2] : NULL;
324     int server_oper = parc > 3 ? (*parv[3] == 'o') : 0;
325     struct Channel *chptr_who = NULL;
326     struct Client *target_p_who = NULL;
327    
328     if (mask != NULL)
329     {
330     collapse(mask);
331    
332     if (*mask == '\0')
333     {
334     sendto_one(client_p, form_str(RPL_ENDOFWHO),
335     me.name, client_p->name, "*");
336     return;
337     }
338     }
339     else
340     {
341     #ifdef OPERSPY_LOG
342     operspy_log(client_p, "WHO", "*");
343     #endif
344     who_global(client_p, NULL, server_oper);
345     sendto_one(client_p, form_str(RPL_ENDOFWHO),
346     me.name, client_p->name, "*");
347     return;
348     }
349    
350     /* /who #channel */
351     if (IsChanPrefix(*mask))
352     {
353     if ((chptr_who = hash_find_channel(mask)) != NULL)
354     {
355     #ifdef OPERSPY_LOG
356     operspy_log(client_p, "WHO", mask);
357     #endif
358     do_who_on_channel(client_p, chptr_who, chptr_who->chname);
359     }
360    
361     sendto_one(client_p, form_str(RPL_ENDOFWHO),
362     me.name, client_p->name, mask);
363     return;
364     }
365    
366     /* /who nick */
367     if ((target_p_who = find_person(client_p, mask)) != NULL)
368     {
369     #ifdef OPERSPY_LOG
370     /* "nick!user@host server\0" */
371     char nuh[NICKLEN + 1 + USERLEN + 1 + HOSTLEN + 1 + HOSTLEN + 1];
372    
373     ircsprintf(nuh, "%s!%s@%s %s", target_p_who->name,
374     target_p_who->username, target_p_who->host,
375     target_p_who->servptr->name);
376     operspy_log(client_p, "WHO", nuh);
377     #endif
378    
379     if (target_p_who->channel.head != NULL)
380     {
381     chptr_who =
382     ((struct Membership *)target_p_who->channel.head->data)->chptr;
383    
384     do_who(client_p, target_p_who, chptr_who->chname,
385     get_member_status(target_p_who->channel.head->data, NO));
386     }
387     else
388     {
389     do_who(client_p, target_p_who, NULL, "");
390     }
391    
392     sendto_one(client_p, form_str(RPL_ENDOFWHO),
393     me.name, client_p->name, mask);
394     return;
395     }
396    
397     #ifdef OPERSPY_LOG
398     operspy_log(client_p, "WHO", parv[2]);
399     #endif
400    
401     /* /who 0 */
402 michael 496 if (!irccmp(mask, "0"))
403 adx 30 who_global(client_p, NULL, server_oper);
404     else
405     who_global(client_p, mask, server_oper);
406    
407     /* nothing else? end of /who. */
408     sendto_one(client_p, form_str(RPL_ENDOFWHO),
409     me.name, client_p->name, mask);
410     }
411    
412     static void
413     operspy_whois(struct Client *client_p, int parc, char *parv[])
414     {
415     const dlink_node *lp;
416     struct Channel *chptr_whois = NULL;
417     struct Client *a2client_p;
418     struct Client *target_p = NULL;
419     char buf[IRCD_BUFSIZE];
420     #ifdef OPERSPY_LOG
421     /* "nick!user@host server\0" */
422     char nuh[NICKLEN + 1 + USERLEN + 1 + HOSTLEN + 1 + HOSTLEN + 1];
423     #endif
424     char *t = NULL;
425     int mlen, tlen;
426     int cur_len = 0;
427     int reply_to_send = NO;
428    
429 michael 290 if (has_wildcards(parv[2]))
430 adx 30 {
431     sendto_one(client_p, ":%s NOTICE %s :Do not use wildcards with this.",
432     me.name, client_p->name);
433     return;
434     }
435    
436     if ((target_p = find_person(client_p, parv[2])) == NULL)
437     {
438     sendto_one(client_p, form_str(ERR_NOSUCHNICK),
439     me.name, client_p->name, parv[2]);
440     return;
441     }
442    
443     #ifdef OPERSPY_LOG
444     ircsprintf(nuh, "%s!%s@%s %s",
445     target_p->name, target_p->username, target_p->host,
446     target_p->servptr->name);
447     operspy_log(client_p, "WHOIS", nuh);
448     #endif
449    
450     a2client_p = target_p->servptr;
451    
452     sendto_one(client_p, form_str(RPL_WHOISUSER), me.name,
453     client_p->name, target_p->name, target_p->username,
454     target_p->host, target_p->info);
455     mlen = ircsprintf(buf, form_str(RPL_WHOISCHANNELS), me.name,
456     client_p->name, target_p->name, "");
457     cur_len = mlen;
458     t = buf + mlen;
459    
460     DLINK_FOREACH(lp, target_p->channel.head)
461     {
462     chptr_whois = ((struct Membership *)lp->data)->chptr;
463    
464     if ((cur_len + strlen(chptr_whois->chname) + 2) > (IRCD_BUFSIZE - 4))
465     {
466     sendto_one(client_p, "%s", buf);
467     cur_len = mlen;
468     t = buf + mlen;
469     }
470    
471     tlen = ircsprintf(t, "%s%s%s ",
472     ShowChannel(client_p, chptr_whois) ? "" : "%",
473     get_member_status((struct Membership *)lp->data, YES),
474     chptr_whois->chname);
475     t += tlen;
476     cur_len += tlen;
477     reply_to_send = YES;
478     }
479    
480     if (reply_to_send == YES)
481     sendto_one(client_p, "%s", buf);
482    
483     sendto_one(client_p, form_str(RPL_WHOISSERVER), me.name,
484     client_p->name, target_p->name, a2client_p->name,
485     a2client_p->info);
486    
487     if (IsOper(target_p))
488     sendto_one(client_p, form_str(IsAdmin(target_p) ? RPL_WHOISADMIN :
489     RPL_WHOISOPERATOR), me.name, client_p->name, target_p->name);
490    
491     if (MyConnect(target_p))
492     sendto_one(client_p, form_str(RPL_WHOISIDLE), me.name,
493     client_p->name, target_p->name, CurrentTime - target_p->localClient->last,
494     target_p->firsttime);
495     sendto_one(client_p, form_str(RPL_ENDOFWHOIS),
496     me.name, client_p->name, parv[2]);
497     }
498    
499     /* extensions for OPERSPY WHO */
500     static void
501     do_who(struct Client *source_p, struct Client *target_p,
502     char *chname, const char *op_flags)
503     {
504     char status[8];
505    
506     ircsprintf(status, "%c%s%s", target_p->away ? 'G' : 'H',
507     IsOper(target_p) ? "*" : "", op_flags);
508     sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
509     (chname) ? (chname) : "*",
510     target_p->username,
511     target_p->host, target_p->servptr->name, target_p->name,
512     status, target_p->hopcount, target_p->info);
513     }
514    
515     static void
516     who_global(struct Client *source_p, char *mask, int server_oper)
517     {
518     struct Client *target_p;
519     dlink_node *lp;
520     int maxmatches = 500;
521    
522     /* list all matching visible clients */
523     DLINK_FOREACH(lp, global_client_list.head)
524     {
525     target_p = lp->data;
526    
527     if (!IsClient(target_p))
528     continue;
529    
530     if (server_oper && !IsOper(target_p))
531     continue;
532    
533     if (!mask ||
534     match(mask, target_p->name) || match(mask, target_p->username) ||
535     match(mask, target_p->host) || match(mask, target_p->servptr->name) ||
536     match(mask, target_p->info) ||
537     (MyClient(target_p) && match(mask, target_p->sockhost)))
538     {
539     if (dlink_list_length(&target_p->channel))
540     {
541     struct Channel *chptr;
542     static char fl[5];
543    
544     chptr = ((struct Membership *)(target_p->channel.head->data))->chptr;
545     snprintf(fl, sizeof(fl), "%s",
546     get_member_status((struct Membership *)(target_p->channel.head->data), NO));
547    
548     do_who(source_p, target_p, chptr->chname, fl);
549     }
550     else
551     do_who(source_p, target_p, NULL, "");
552    
553     if (maxmatches > 0)
554     {
555     if (--maxmatches == 0)
556     return;
557     }
558     }
559     }
560     }
561    
562     static void
563     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
564     char *chname)
565     {
566     dlink_node *ptr;
567     struct Membership *ms;
568    
569     DLINK_FOREACH(ptr, chptr->members.head)
570     {
571     ms = ptr->data;
572     do_who(source_p, ms->client_p, chname, get_member_status(ms, NO));
573     }
574     }
575    
576     #ifdef OPERSPY_LOG
577     static void
578     operspy_log(struct Client *source_p, const char *command, const char *target)
579     {
580     #ifdef OPERSPY_LOGFILE
581     size_t nbytes = 0;
582     FBFILE *operspy_fb;
583     const char *opername = source_p->name;
584     char linebuf[IRCD_BUFSIZE], logfile[IRCD_BUFSIZE];
585     #endif
586    
587     assert(source_p != NULL);
588    
589     #ifdef OPERSPY_LOGFILE
590     if (IsOper(source_p) && MyClient(source_p))
591 db 161 opername = source_p->localClient->auth_oper;
592 adx 30 else if (!MyClient(source_p))
593     opername = "remote";
594    
595     ircsprintf(logfile, "%s/operspy.%s.log", LOGPATH, opername);
596     if ((operspy_fb = fbopen(logfile, "a")) == NULL)
597     return;
598    
599     nbytes = ircsprintf(linebuf, "[%s] OPERSPY %s %s %s\n",
600     smalldate(CurrentTime),
601     get_oper_name(source_p),
602     command, target);
603     fbputs(linebuf, operspy_fb, nbytes);
604     fbclose(operspy_fb);
605     #endif
606    
607     #ifdef OPERSPY_NOTICE
608     sendto_realops_flags(UMODE_SPY, L_ALL, "OPERSPY %s %s %s",
609     get_oper_name(source_p), command, target);
610     #endif
611    
612     if (MyClient(source_p))
613     sendto_match_servs(source_p, "*", CAP_ENCAP, "ENCAP * OPERSPY %s :%s",
614     command, target);
615     }
616     #endif /* OPERSPY_LOG */

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision