ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/contrib/m_operspy.c
Revision: 1325
Committed: Sat Mar 31 10:29:02 2012 UTC (12 years ago) by michael
Content type: text/x-csrc
File size: 17489 byte(s)
Log Message:
- Get rid of fileio.c. Replace some ircsprintf() with snprintf() while on it

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

Properties

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