ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/m_whois.c
Revision: 270
Committed: Mon Nov 14 19:39:35 2005 UTC (20 years, 8 months ago) by adx
Content type: text/x-csrc
File size: 11682 byte(s)
Log Message:
+ ported rate limiting fixes from 7.2

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * m_whois.c: Shows who a user is.
4     *
5     * Copyright (C) 2005 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26     #include "common.h"
27     #include "handlers.h"
28     #include "client.h"
29     #include "hash.h"
30     #include "channel.h"
31     #include "channel_mode.h"
32     #include "ircd.h"
33     #include "numeric.h"
34     #include "s_conf.h"
35     #include "s_serv.h"
36     #include "send.h"
37     #include "msg.h"
38     #include "parse.h"
39     #include "modules.h"
40    
41     static void do_whois(struct Client *, int, char **);
42     static int single_whois(struct Client *, struct Client *);
43     static void whois_person(struct Client *, struct Client *);
44     static int global_whois(struct Client *, const char *);
45    
46     static void m_whois(struct Client *, struct Client *, int, char *[]);
47     static void mo_whois(struct Client *, struct Client *, int, char *[]);
48    
49     struct Message whois_msgtab = {
50     "WHOIS", 0, 0, 0, 0, MFLG_SLOW, 0,
51     { m_unregistered, m_whois, mo_whois, m_ignore, mo_whois, m_ignore }
52     };
53    
54     #ifndef STATIC_MODULES
55 knight 31 const char *_version = "$Revision$";
56 adx 30 static struct Callback *whois_cb;
57    
58     static void *
59     va_whois(va_list args)
60     {
61     struct Client *source_p = va_arg(args, struct Client *);
62     int parc = va_arg(args, int);
63     char **parv = va_arg(args, char **);
64    
65     do_whois(source_p, parc, parv);
66     return NULL;
67     }
68    
69     void
70     _modinit(void)
71     {
72     whois_cb = register_callback("doing_whois", va_whois);
73     mod_add_cmd(&whois_msgtab);
74     }
75    
76     void
77     _moddeinit(void)
78     {
79     mod_del_cmd(&whois_msgtab);
80     uninstall_hook(whois_cb, va_whois);
81     }
82     #endif
83    
84     /*
85     ** m_whois
86     ** parv[0] = sender prefix
87     ** parv[1] = nickname masklist
88     */
89     static void
90     m_whois(struct Client *client_p, struct Client *source_p,
91     int parc, char *parv[])
92     {
93     static time_t last_used = 0;
94    
95     if (parc < 2 || EmptyString(parv[1]))
96     {
97     sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
98     me.name, source_p->name);
99     return;
100     }
101    
102 michael 92 if (parc > 2 && !EmptyString(parv[2]))
103 adx 30 {
104     /* seeing as this is going across servers, we should limit it */
105     if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
106     {
107     sendto_one(source_p, form_str(RPL_LOAD2HI),
108     me.name, source_p->name);
109     return;
110     }
111     else
112     last_used = CurrentTime;
113    
114     /* if we have serverhide enabled, they can either ask the clients
115     * server, or our server.. I dont see why they would need to ask
116     * anything else for info about the client.. --fl_
117     */
118     if (ConfigFileEntry.disable_remote)
119     parv[1] = parv[2];
120    
121     if (hunt_server(client_p, source_p, ":%s WHOIS %s :%s", 1,
122     parc, parv) != HUNTED_ISME)
123     return;
124    
125     parv[1] = parv[2];
126     }
127    
128     #ifdef STATIC_MODULES
129     do_whois(source_p, parc, parv);
130     #else
131     execute_callback(whois_cb, source_p, parc, parv);
132     #endif
133     }
134    
135     /*
136     ** mo_whois
137     ** parv[0] = sender prefix
138     ** parv[1] = nickname masklist
139     */
140     static void
141     mo_whois(struct Client *client_p, struct Client *source_p,
142     int parc, char *parv[])
143     {
144     if (parc < 2 || EmptyString(parv[1]))
145     {
146     sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
147     me.name, source_p->name);
148     return;
149     }
150    
151 michael 92 if (parc > 2 && !EmptyString(parv[2]))
152 adx 30 {
153     if (hunt_server(client_p, source_p, ":%s WHOIS %s :%s", 1,
154     parc, parv) != HUNTED_ISME)
155     return;
156    
157     parv[1] = parv[2];
158     }
159    
160     #ifdef STATIC_MODULES
161     do_whois(source_p, parc, parv);
162     #else
163     execute_callback(whois_cb, source_p, parc, parv);
164     #endif
165     }
166    
167     /* do_whois()
168     *
169     * inputs - pointer to /whois source
170     * - number of parameters
171     * - pointer to parameters array
172     * output - pointer to void
173     * side effects - Does whois
174     */
175     static void
176     do_whois(struct Client *source_p, int parc, char **parv)
177     {
178 adx 270 static time_t last_used = 0;
179 adx 30 struct Client *target_p;
180     char *nick;
181     char *p = NULL;
182     int found = 0;
183    
184     nick = parv[1];
185     while (*nick == ',')
186     nick++;
187 adx 270 if ((p = strchr(nick, ',')) != NULL)
188 adx 30 *p = '\0';
189    
190     if (*nick == '\0')
191     return;
192    
193     collapse(nick);
194    
195     if (strpbrk(nick, "?#*") == NULL)
196     {
197     if ((target_p = find_client(nick)) != NULL)
198     {
199     if (IsServer(source_p->from))
200 michael 92 client_burst_if_needed(source_p->from, target_p);
201 adx 30
202     if (IsClient(target_p))
203     {
204 michael 92 whois_person(source_p, target_p);
205     found = 1;
206 adx 30 }
207     }
208     else if (!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
209     {
210     if (parc > 2)
211     sendto_one(uplink,":%s WHOIS %s :%s",
212     source_p->name, nick, nick);
213     else
214     sendto_one(uplink,":%s WHOIS %s",
215     source_p->name, nick);
216     return;
217     }
218     }
219     else /* wilds is true */
220     {
221     /* disallow wild card whois on lazylink leafs for now */
222     if (!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
223     return;
224    
225 adx 270 if (!IsOper(source_p))
226     {
227     if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
228     {
229     sendto_one(source_p, form_str(RPL_LOAD2HI),
230     me.name, source_p->name);
231     return;
232     }
233     else
234     last_used = CurrentTime;
235     }
236    
237 adx 30 /* Oh-oh wilds is true so have to do it the hard expensive way */
238     if (MyClient(source_p))
239     found = global_whois(source_p, nick);
240     }
241    
242     if (!found)
243     {
244     if (!IsDigit(*nick))
245     sendto_one(source_p, form_str(ERR_NOSUCHNICK),
246 michael 92 me.name, source_p->name, nick);
247 adx 30 }
248    
249     sendto_one(source_p, form_str(RPL_ENDOFWHOIS),
250     me.name, source_p->name, parv[1]);
251     }
252    
253     /* global_whois()
254     *
255     * Inputs - source_p client to report to
256     * - target_p client to report on
257     * Output - if found return 1
258     * Side Effects - do a single whois on given client
259     * writing results to source_p
260     */
261     static int
262     global_whois(struct Client *source_p, const char *nick)
263     {
264 michael 92 dlink_node *ptr = NULL;
265     struct Client *target_p = NULL;
266 adx 30 int found = 0;
267    
268     DLINK_FOREACH(ptr, global_client_list.head)
269     {
270     target_p = ptr->data;
271    
272     if (!IsClient(target_p))
273     continue;
274    
275     if (!match(nick, target_p->name))
276     continue;
277    
278     assert(target_p->servptr != NULL);
279    
280     /* 'Rules' established for sending a WHOIS reply:
281     *
282     *
283     * - if wildcards are being used dont send a reply if
284     * the querier isnt any common channels and the
285     * client in question is invisible and wildcards are
286     * in use (allow exact matches only);
287     *
288     * - only send replies about common or public channels
289     * the target user(s) are on;
290     */
291    
292     found |= single_whois(source_p, target_p);
293     }
294    
295 michael 92 return found;
296 adx 30 }
297    
298     /* single_whois()
299     *
300     * Inputs - source_p client to report to
301     * - target_p client to report on
302     * Output - if found return 1
303     * Side Effects - do a single whois on given client
304     * writing results to source_p
305     */
306     static int
307     single_whois(struct Client *source_p, struct Client *target_p)
308     {
309 michael 92 dlink_node *ptr = NULL;
310     struct Channel *chptr = NULL;
311 adx 30
312     if (!IsInvisible(target_p) || target_p == source_p)
313     {
314     /* always show user if they are visible (no +i) */
315     whois_person(source_p, target_p);
316     return 1;
317     }
318    
319     /* target_p is +i. Check if it is on any common channels with source_p */
320     DLINK_FOREACH(ptr, target_p->channel.head)
321     {
322     chptr = ((struct Membership *) ptr->data)->chptr;
323     if (IsMember(source_p, chptr))
324     {
325     whois_person(source_p, target_p);
326     return 1;
327     }
328     }
329    
330     return 0;
331     }
332    
333     /* whois_person()
334     *
335     * inputs - source_p client to report to
336     * - target_p client to report on
337     * output - NONE
338     * side effects -
339     */
340     static void
341     whois_person(struct Client *source_p, struct Client *target_p)
342     {
343     char buf[IRCD_BUFSIZE];
344     dlink_node *lp;
345     struct Client *server_p;
346     struct Channel *chptr;
347     struct Membership *ms;
348     int cur_len = 0;
349     int mlen;
350     char *t = NULL;
351     int tlen;
352     int reply_to_send = NO;
353    
354     server_p = target_p->servptr;
355    
356     sendto_one(source_p, form_str(RPL_WHOISUSER),
357     me.name, source_p->name, target_p->name,
358     target_p->username, target_p->host, target_p->info);
359    
360     cur_len = mlen = ircsprintf(buf, form_str(RPL_WHOISCHANNELS),
361     me.name, source_p->name, target_p->name, "");
362     t = buf + mlen;
363    
364     DLINK_FOREACH(lp, target_p->channel.head)
365     {
366     ms = lp->data;
367     chptr = ms->chptr;
368    
369     if (ShowChannel(source_p, chptr))
370     {
371     /* Don't show local channels if user is doing a remote whois */
372     if (!MyConnect(source_p) && (chptr->chname[0] == '&'))
373 michael 92 continue;
374 adx 30
375     if ((cur_len + 3 + strlen(chptr->chname) + 1) > (IRCD_BUFSIZE - 2))
376     {
377 michael 92 *(t - 1) = '\0';
378     sendto_one(source_p, "%s", buf);
379     cur_len = mlen;
380     t = buf + mlen;
381 adx 30 }
382    
383     tlen = ircsprintf(t, "%s%s ", get_member_status(ms, YES), chptr->chname);
384     t += tlen;
385     cur_len += tlen;
386     reply_to_send = YES;
387     }
388     }
389    
390     if (reply_to_send)
391     {
392     *(t - 1) = '\0';
393     sendto_one(source_p, "%s", buf);
394     }
395    
396     if (IsOper(source_p) || !ConfigServerHide.hide_servers || target_p == source_p)
397     sendto_one(source_p, form_str(RPL_WHOISSERVER),
398     me.name, source_p->name, target_p->name,
399     server_p->name, server_p->info);
400     else
401     sendto_one(source_p, form_str(RPL_WHOISSERVER),
402 michael 92 me.name, source_p->name, target_p->name,
403 adx 30 ConfigServerHide.hidden_name,
404 michael 92 ServerInfo.network_desc);
405 adx 30
406     if (target_p->away != NULL)
407     sendto_one(source_p, form_str(RPL_AWAY),
408     me.name, source_p->name, target_p->name,
409     target_p->away);
410    
411     if (IsOper(target_p))
412     sendto_one(source_p, form_str((IsAdmin(target_p) &&
413     !IsOperHiddenAdmin(target_p)) ? RPL_WHOISADMIN :
414     RPL_WHOISOPERATOR), me.name, source_p->name, target_p->name);
415    
416     if (IsOper(source_p) && IsCaptured(target_p))
417     sendto_one(source_p, form_str(RPL_ISCAPTURED),
418     me.name, source_p->name, target_p->name);
419    
420     if (ConfigFileEntry.use_whois_actually && (target_p->sockhost[0] != '\0') &&
421     !(ConfigFileEntry.hide_spoof_ips && IsIPSpoof(target_p)) &&
422     !(target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
423     {
424     if (IsAdmin(source_p) || source_p == target_p)
425     sendto_one(source_p, form_str(RPL_WHOISACTUALLY),
426     me.name, source_p->name, target_p->name, target_p->sockhost);
427     else
428     sendto_one(source_p, form_str(RPL_WHOISACTUALLY),
429     me.name, source_p->name, target_p->name,
430     IsIPSpoof(target_p) || IsOper(target_p) ?
431 michael 92 "255.255.255.255" : target_p->sockhost);
432 adx 30 }
433    
434     if (MyConnect(target_p)) /* Can't do any of this if not local! db */
435     {
436     #ifdef HAVE_LIBCRYPTO
437     if (target_p->localClient->fd.ssl)
438     sendto_one(source_p, form_str(RPL_WHOISSSL),
439     me.name, source_p->name, target_p->name);
440     #endif
441     sendto_one(source_p, form_str(RPL_WHOISIDLE),
442     me.name, source_p->name, target_p->name,
443     CurrentTime - target_p->localClient->last,
444     target_p->firsttime);
445     }
446     }

Properties

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