ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/contrib/m_operspy.c
Revision: 161
Committed: Thu Oct 20 02:10:27 2005 UTC (19 years, 10 months ago) by db
Content type: text/x-csrc
File size: 17101 byte(s)
Log Message:
- Make contrib compile with HEAD


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

Properties

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