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

Properties

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