ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/contrib/m_operspy.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (20 years, 10 months ago) by lusky
Content type: text/x-csrc
File size: 17424 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


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     /* the way to go with this, rather than temporarily setting -sp,
293     * is to temporarily add our client to the member list. then
294     * we can also list +i users. an unfortunate side-effect of this
295     * is that your nickname shows up in the list. for now, there is
296     * no easy way around it.
297     */
298     add_user_to_channel(chptr_names, client_p, CHFL_CHANOP, NO);
299     channel_member_names(client_p, chptr_names, 1);
300     remove_user_from_channel(find_channel_link(client_p, chptr_names));
301     }
302    
303     static void
304     operspy_topic(struct Client *client_p, int parc, char *parv[])
305     {
306     const struct Channel *chptr_topic = NULL;
307    
308     if ((chptr_topic = hash_find_channel(parv[2])) == NULL)
309     {
310     sendto_one(client_p, form_str(ERR_NOSUCHCHANNEL),
311     me.name, client_p->name, parv[2]);
312     return;
313     }
314    
315     #ifdef OPERSPY_LOG
316     operspy_log(client_p, "TOPIC", parv[2]);
317     #endif
318    
319     if (chptr_topic->topic == NULL)
320     sendto_one(client_p, form_str(RPL_NOTOPIC),
321     me.name, client_p->name, parv[2]);
322     else
323     {
324     sendto_one(client_p, form_str(RPL_TOPIC), me.name, client_p->name,
325     chptr_topic->chname, chptr_topic->topic);
326     sendto_one(client_p, form_str(RPL_TOPICWHOTIME), me.name,
327     client_p->name, chptr_topic->chname, chptr_topic->topic_info,
328     chptr_topic->topic_time);
329     }
330     }
331    
332     static void
333     operspy_who(struct Client *client_p, int parc, char *parv[])
334     {
335     char *mask = parc > 2 ? parv[2] : NULL;
336     int server_oper = parc > 3 ? (*parv[3] == 'o') : 0;
337     struct Channel *chptr_who = NULL;
338     struct Client *target_p_who = NULL;
339    
340     if (mask != NULL)
341     {
342     collapse(mask);
343    
344     if (*mask == '\0')
345     {
346     sendto_one(client_p, form_str(RPL_ENDOFWHO),
347     me.name, client_p->name, "*");
348     return;
349     }
350     }
351     else
352     {
353     #ifdef OPERSPY_LOG
354     operspy_log(client_p, "WHO", "*");
355     #endif
356     who_global(client_p, NULL, server_oper);
357     sendto_one(client_p, form_str(RPL_ENDOFWHO),
358     me.name, client_p->name, "*");
359     return;
360     }
361    
362     /* /who #channel */
363     if (IsChanPrefix(*mask))
364     {
365     if ((chptr_who = hash_find_channel(mask)) != NULL)
366     {
367     #ifdef OPERSPY_LOG
368     operspy_log(client_p, "WHO", mask);
369     #endif
370     do_who_on_channel(client_p, chptr_who, chptr_who->chname);
371     }
372    
373     sendto_one(client_p, form_str(RPL_ENDOFWHO),
374     me.name, client_p->name, mask);
375     return;
376     }
377    
378     /* /who nick */
379     if ((target_p_who = find_person(client_p, mask)) != NULL)
380     {
381     #ifdef OPERSPY_LOG
382     /* "nick!user@host server\0" */
383     char nuh[NICKLEN + 1 + USERLEN + 1 + HOSTLEN + 1 + HOSTLEN + 1];
384    
385     ircsprintf(nuh, "%s!%s@%s %s", target_p_who->name,
386     target_p_who->username, target_p_who->host,
387     target_p_who->servptr->name);
388     operspy_log(client_p, "WHO", nuh);
389     #endif
390    
391     if (target_p_who->channel.head != NULL)
392     {
393     chptr_who =
394     ((struct Membership *)target_p_who->channel.head->data)->chptr;
395    
396     do_who(client_p, target_p_who, chptr_who->chname,
397     get_member_status(target_p_who->channel.head->data, NO));
398     }
399     else
400     {
401     do_who(client_p, target_p_who, NULL, "");
402     }
403    
404     sendto_one(client_p, form_str(RPL_ENDOFWHO),
405     me.name, client_p->name, mask);
406     return;
407     }
408    
409     #ifdef OPERSPY_LOG
410     operspy_log(client_p, "WHO", parv[2]);
411     #endif
412    
413     /* /who 0 */
414     if ((*(mask + 1) == '\0') && (*mask == '0'))
415     who_global(client_p, NULL, server_oper);
416     else
417     who_global(client_p, mask, server_oper);
418    
419     /* nothing else? end of /who. */
420     sendto_one(client_p, form_str(RPL_ENDOFWHO),
421     me.name, client_p->name, mask);
422     }
423    
424     static void
425     operspy_whois(struct Client *client_p, int parc, char *parv[])
426     {
427     const dlink_node *lp;
428     struct Channel *chptr_whois = NULL;
429     struct Client *a2client_p;
430     struct Client *target_p = NULL;
431     char buf[IRCD_BUFSIZE];
432     #ifdef OPERSPY_LOG
433     /* "nick!user@host server\0" */
434     char nuh[NICKLEN + 1 + USERLEN + 1 + HOSTLEN + 1 + HOSTLEN + 1];
435     #endif
436     char *t = NULL;
437     int mlen, tlen;
438     int cur_len = 0;
439     int reply_to_send = NO;
440    
441     if (strchr(parv[2], '?') || strchr(parv[2], '*'))
442     {
443     sendto_one(client_p, ":%s NOTICE %s :Do not use wildcards with this.",
444     me.name, client_p->name);
445     return;
446     }
447    
448     if ((target_p = find_person(client_p, parv[2])) == NULL)
449     {
450     sendto_one(client_p, form_str(ERR_NOSUCHNICK),
451     me.name, client_p->name, parv[2]);
452     return;
453     }
454    
455     #ifdef OPERSPY_LOG
456     ircsprintf(nuh, "%s!%s@%s %s",
457     target_p->name, target_p->username, target_p->host,
458     target_p->servptr->name);
459     operspy_log(client_p, "WHOIS", nuh);
460     #endif
461    
462     a2client_p = target_p->servptr;
463    
464     sendto_one(client_p, form_str(RPL_WHOISUSER), me.name,
465     client_p->name, target_p->name, target_p->username,
466     target_p->host, target_p->info);
467     mlen = ircsprintf(buf, form_str(RPL_WHOISCHANNELS), me.name,
468     client_p->name, target_p->name, "");
469     cur_len = mlen;
470     t = buf + mlen;
471    
472     DLINK_FOREACH(lp, target_p->channel.head)
473     {
474     chptr_whois = ((struct Membership *)lp->data)->chptr;
475    
476     if ((cur_len + strlen(chptr_whois->chname) + 2) > (IRCD_BUFSIZE - 4))
477     {
478     sendto_one(client_p, "%s", buf);
479     cur_len = mlen;
480     t = buf + mlen;
481     }
482    
483     tlen = ircsprintf(t, "%s%s%s ",
484     ShowChannel(client_p, chptr_whois) ? "" : "%",
485     get_member_status((struct Membership *)lp->data, YES),
486     chptr_whois->chname);
487     t += tlen;
488     cur_len += tlen;
489     reply_to_send = YES;
490     }
491    
492     if (reply_to_send == YES)
493     sendto_one(client_p, "%s", buf);
494    
495     sendto_one(client_p, form_str(RPL_WHOISSERVER), me.name,
496     client_p->name, target_p->name, a2client_p->name,
497     a2client_p->info);
498    
499     if (IsOper(target_p))
500     sendto_one(client_p, form_str(IsAdmin(target_p) ? RPL_WHOISADMIN :
501     RPL_WHOISOPERATOR), me.name, client_p->name, target_p->name);
502    
503     if (MyConnect(target_p))
504     sendto_one(client_p, form_str(RPL_WHOISIDLE), me.name,
505     client_p->name, target_p->name, CurrentTime - target_p->localClient->last,
506     target_p->firsttime);
507     sendto_one(client_p, form_str(RPL_ENDOFWHOIS),
508     me.name, client_p->name, parv[2]);
509     }
510    
511     /* extensions for OPERSPY WHO */
512     static void
513     do_who(struct Client *source_p, struct Client *target_p,
514     char *chname, const char *op_flags)
515     {
516     char status[8];
517    
518     ircsprintf(status, "%c%s%s", target_p->away ? 'G' : 'H',
519     IsOper(target_p) ? "*" : "", op_flags);
520     sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
521     (chname) ? (chname) : "*",
522     target_p->username,
523     target_p->host, target_p->servptr->name, target_p->name,
524     status, target_p->hopcount, target_p->info);
525     }
526    
527     static void
528     who_global(struct Client *source_p, char *mask, int server_oper)
529     {
530     struct Client *target_p;
531     dlink_node *lp;
532     int maxmatches = 500;
533    
534     /* list all matching visible clients */
535     DLINK_FOREACH(lp, global_client_list.head)
536     {
537     target_p = lp->data;
538    
539     if (!IsClient(target_p))
540     continue;
541    
542     if (server_oper && !IsOper(target_p))
543     continue;
544    
545     if (!mask ||
546     match(mask, target_p->name) || match(mask, target_p->username) ||
547     match(mask, target_p->host) || match(mask, target_p->servptr->name) ||
548     match(mask, target_p->info) ||
549     (MyClient(target_p) && match(mask, target_p->sockhost)))
550     {
551     if (dlink_list_length(&target_p->channel))
552     {
553     struct Channel *chptr;
554     static char fl[5];
555    
556     chptr = ((struct Membership *)(target_p->channel.head->data))->chptr;
557     snprintf(fl, sizeof(fl), "%s",
558     get_member_status((struct Membership *)(target_p->channel.head->data), NO));
559    
560     do_who(source_p, target_p, chptr->chname, fl);
561     }
562     else
563     do_who(source_p, target_p, NULL, "");
564    
565     if (maxmatches > 0)
566     {
567     if (--maxmatches == 0)
568     return;
569     }
570     }
571     }
572     }
573    
574     static void
575     do_who_on_channel(struct Client *source_p, struct Channel *chptr,
576     char *chname)
577     {
578     dlink_node *ptr;
579     struct Membership *ms;
580    
581     DLINK_FOREACH(ptr, chptr->members.head)
582     {
583     ms = ptr->data;
584     do_who(source_p, ms->client_p, chname, get_member_status(ms, NO));
585     }
586     }
587    
588     #ifdef OPERSPY_LOG
589     static void
590     operspy_log(struct Client *source_p, const char *command, const char *target)
591     {
592     struct ConfItem *conf = NULL;
593     #ifdef OPERSPY_LOGFILE
594     size_t nbytes = 0;
595     FBFILE *operspy_fb;
596     dlink_node *cnode;
597     const char *opername = source_p->name;
598     char linebuf[IRCD_BUFSIZE], logfile[IRCD_BUFSIZE];
599     #endif
600    
601     assert(source_p != NULL);
602    
603     #ifdef OPERSPY_LOGFILE
604     if (IsOper(source_p) && MyClient(source_p))
605     {
606     DLINK_FOREACH(cnode, source_p->localClient->confs.head)
607     {
608     conf = cnode->data;
609    
610     if (conf->type == OPER_TYPE)
611     opername = conf->name;
612     }
613     }
614     else if (!MyClient(source_p))
615     opername = "remote";
616    
617     ircsprintf(logfile, "%s/operspy.%s.log", LOGPATH, opername);
618     if ((operspy_fb = fbopen(logfile, "a")) == NULL)
619     return;
620    
621     nbytes = ircsprintf(linebuf, "[%s] OPERSPY %s %s %s\n",
622     smalldate(CurrentTime),
623     get_oper_name(source_p),
624     command, target);
625     fbputs(linebuf, operspy_fb, nbytes);
626     fbclose(operspy_fb);
627     #endif
628    
629     #ifdef OPERSPY_NOTICE
630     sendto_realops_flags(UMODE_SPY, L_ALL, "OPERSPY %s %s %s",
631     get_oper_name(source_p), command, target);
632     #endif
633    
634     if (MyClient(source_p))
635     sendto_match_servs(source_p, "*", CAP_ENCAP, "ENCAP * OPERSPY %s :%s",
636     command, target);
637     }
638     #endif /* OPERSPY_LOG */

Properties

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