ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/contrib/m_operspy.c
Revision: 30
Committed: Sun Oct 2 20:03:27 2005 UTC (18 years, 6 months ago) by adx
Content type: text/x-csrc
File size: 17484 byte(s)
Log Message:
- imported sources
- can be moved later according to the directory/branching scheme,
  but we need the svn up

File Contents

# Content
1 /************************************************************************
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 * $Id: m_operspy.c,v 1.67 2005/10/01 14:29:47 michael Exp $
20 */
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 const char *_version = "$Revision: 1.67 $";
144 #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"