ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.3/contrib/m_operspy.c
Revision: 1029
Committed: Sun Nov 8 13:10:50 2009 UTC (14 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 17538 byte(s)
Log Message:
- branch off trunk to create 7.3 branch

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$
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 "list.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$";
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 /*
293 * the way to go with this, rather than temporarily setting -sp,
294 * 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 if (IsMember(client_p, chptr_names))
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 }
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