ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/contrib/m_operspy.c
Revision: 812
Committed: Thu Sep 7 09:41:54 2006 UTC (17 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 16989 byte(s)
Log Message:
- Imported contrib/

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 801 2006-08-30 16:54:25Z adx $
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 "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 "server.h"
41 #include "send.h"
42 #include "msg.h"
43 #include "parse.h"
44 #include "conf/modules.h"
45 #include "hash.h"
46 #include "user.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 { m_ignore, m_not_oper, ms_operspy, ms_operspy, mo_operspy, m_ignore }
97 };
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 INIT_MODULE(m_operspy, "$Revision: 801 $")
125 {
126 mod_add_cmd(&operspy_msgtab);
127 }
128
129 CLEANUP_MODULE
130 {
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 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 }
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 /*
276 * the way to go with this, rather than temporarily setting -sp,
277 * 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 */
282 if (IsMember(client_p, chptr_names))
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 }
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 if (!irccmp(mask, "0"))
403 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 if (has_wildcards(parv[2], NO))
430 {
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 opername = source_p->localClient->auth_oper;
592 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"