1 |
adx |
30 |
/* |
2 |
michael |
2820 |
* ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd) |
3 |
adx |
30 |
* |
4 |
michael |
9101 |
* Copyright (c) 1997-2020 ircd-hybrid development team |
5 |
adx |
30 |
* |
6 |
|
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
|
* it under the terms of the GNU General Public License as published by |
8 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
michael |
4565 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
19 |
adx |
30 |
* USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
michael |
2820 |
/*! \file m_whois.c |
23 |
|
|
* \brief Includes required functions for processing the WHOIS command. |
24 |
|
|
* \version $Id$ |
25 |
|
|
*/ |
26 |
|
|
|
27 |
adx |
30 |
#include "stdinc.h" |
28 |
michael |
1011 |
#include "list.h" |
29 |
adx |
30 |
#include "client.h" |
30 |
michael |
8484 |
#include "client_svstag.h" |
31 |
adx |
30 |
#include "hash.h" |
32 |
|
|
#include "channel.h" |
33 |
|
|
#include "channel_mode.h" |
34 |
|
|
#include "ircd.h" |
35 |
|
|
#include "numeric.h" |
36 |
michael |
1309 |
#include "conf.h" |
37 |
michael |
3347 |
#include "misc.h" |
38 |
|
|
#include "server.h" |
39 |
|
|
#include "user.h" |
40 |
adx |
30 |
#include "send.h" |
41 |
|
|
#include "irc_string.h" |
42 |
|
|
#include "parse.h" |
43 |
|
|
#include "modules.h" |
44 |
|
|
|
45 |
michael |
1243 |
|
46 |
michael |
3513 |
static int |
47 |
michael |
9081 |
whois_can_see_channels(struct Channel *channel, |
48 |
michael |
3513 |
struct Client *source_p, |
49 |
|
|
struct Client *target_p) |
50 |
|
|
{ |
51 |
michael |
9081 |
if (PubChannel(channel) && !HasUMode(target_p, UMODE_HIDECHANS)) |
52 |
michael |
3513 |
return 1; |
53 |
|
|
|
54 |
michael |
9081 |
if (source_p == target_p || IsMember(source_p, channel)) |
55 |
michael |
3513 |
return 1; |
56 |
|
|
|
57 |
michael |
5528 |
if (HasUMode(source_p, UMODE_OPER)) |
58 |
michael |
3513 |
return 2; |
59 |
|
|
return 0; |
60 |
|
|
} |
61 |
|
|
|
62 |
adx |
30 |
/* whois_person() |
63 |
|
|
* |
64 |
|
|
* inputs - source_p client to report to |
65 |
|
|
* - target_p client to report on |
66 |
|
|
* output - NONE |
67 |
|
|
* side effects - |
68 |
|
|
*/ |
69 |
|
|
static void |
70 |
|
|
whois_person(struct Client *source_p, struct Client *target_p) |
71 |
|
|
{ |
72 |
michael |
7687 |
dlink_node *node; |
73 |
michael |
5551 |
const struct ServicesTag *svstag = NULL; |
74 |
adx |
30 |
|
75 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISUSER, target_p->name, |
76 |
|
|
target_p->username, target_p->host, |
77 |
|
|
target_p->info); |
78 |
adx |
30 |
|
79 |
michael |
9419 |
if (dlink_list_length(&target_p->channel)) |
80 |
adx |
30 |
{ |
81 |
michael |
9419 |
char buf[IRCD_BUFSIZE]; |
82 |
|
|
char *bufptr = buf; |
83 |
adx |
30 |
|
84 |
michael |
9419 |
/* :me.name 319 source_p->name target_p->name :~@#chan1 +#chan2 #chan3 ...\r\n */ |
85 |
|
|
/* 1 23456 7 89 0 1 */ |
86 |
|
|
size_t len = strlen(me.name) + strlen(source_p->name) + strlen(target_p->name) + 11; |
87 |
|
|
|
88 |
|
|
DLINK_FOREACH(node, target_p->channel.head) |
89 |
adx |
30 |
{ |
90 |
michael |
9419 |
const struct ChannelMember *member = node->data; |
91 |
|
|
int show = whois_can_see_channels(member->channel, source_p, target_p); |
92 |
|
|
|
93 |
|
|
if (show) |
94 |
adx |
30 |
{ |
95 |
michael |
9419 |
if ((bufptr - buf) + member->channel->name_len + 1 + (show == 2) + 3 /* 3 for @%+ */ + len > sizeof(buf)) |
96 |
|
|
{ |
97 |
|
|
*(bufptr - 1) = '\0'; |
98 |
|
|
sendto_one_numeric(source_p, &me, RPL_WHOISCHANNELS, target_p->name, buf); |
99 |
|
|
bufptr = buf; |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
bufptr += snprintf(bufptr, sizeof(buf) - (bufptr - buf), "%s%s%s ", |
103 |
|
|
show == 2 ? "~" : "", get_member_status(member, true), member->channel->name); |
104 |
adx |
30 |
} |
105 |
michael |
9419 |
} |
106 |
adx |
30 |
|
107 |
michael |
9419 |
if (bufptr != buf) |
108 |
|
|
{ |
109 |
|
|
*(bufptr - 1) = '\0'; |
110 |
|
|
sendto_one_numeric(source_p, &me, RPL_WHOISCHANNELS, target_p->name, buf); |
111 |
adx |
30 |
} |
112 |
|
|
} |
113 |
|
|
|
114 |
michael |
2748 |
if ((ConfigServerHide.hide_servers || IsHidden(target_p->servptr)) && |
115 |
michael |
7870 |
!(HasUMode(source_p, UMODE_OPER) || source_p == target_p)) |
116 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISSERVER, target_p->name, |
117 |
|
|
ConfigServerHide.hidden_name, |
118 |
michael |
4340 |
ConfigServerInfo.network_desc); |
119 |
adx |
30 |
else |
120 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISSERVER, target_p->name, |
121 |
|
|
target_p->servptr->name, target_p->servptr->info); |
122 |
adx |
30 |
|
123 |
michael |
1164 |
if (HasUMode(target_p, UMODE_REGISTERED)) |
124 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISREGNICK, target_p->name); |
125 |
michael |
1158 |
|
126 |
michael |
6827 |
if (strcmp(target_p->account, "*")) |
127 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISACCOUNT, target_p->name, |
128 |
michael |
4819 |
target_p->account, "is"); |
129 |
michael |
2478 |
|
130 |
michael |
1483 |
if (target_p->away[0]) |
131 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_AWAY, target_p->name, |
132 |
|
|
target_p->away); |
133 |
adx |
30 |
|
134 |
michael |
5517 |
if (HasUMode(target_p, UMODE_CALLERID | UMODE_SOFTCALLERID)) |
135 |
michael |
2580 |
{ |
136 |
michael |
8719 |
bool callerid = HasUMode(target_p, UMODE_CALLERID) != 0; |
137 |
michael |
3109 |
|
138 |
|
|
sendto_one_numeric(source_p, &me, RPL_TARGUMODEG, target_p->name, |
139 |
|
|
callerid ? "+g" : "+G", |
140 |
|
|
callerid ? "server side ignore" : |
141 |
|
|
"server side ignore with the exception of common channels"); |
142 |
michael |
2580 |
} |
143 |
adx |
660 |
|
144 |
michael |
8481 |
if (HasUMode(target_p, UMODE_OPER) || HasFlag(target_p, FLAGS_SERVICE)) |
145 |
|
|
{ |
146 |
|
|
if (!HasUMode(target_p, UMODE_HIDDEN) || HasUMode(source_p, UMODE_OPER)) |
147 |
|
|
{ |
148 |
|
|
if (target_p->svstags.head) |
149 |
|
|
svstag = target_p->svstags.head->data; |
150 |
michael |
5551 |
|
151 |
michael |
8603 |
if (svstag == NULL || svstag->numeric != RPL_WHOISOPERATOR) |
152 |
michael |
8481 |
{ |
153 |
|
|
const char *text; |
154 |
|
|
if (HasFlag(target_p, FLAGS_SERVICE)) |
155 |
|
|
text = "is a Network Service"; |
156 |
|
|
else if (HasUMode(target_p, UMODE_ADMIN)) |
157 |
|
|
text = "is a Server Administrator"; |
158 |
|
|
else /* HasUMode(target_p, UMODE_OPER) == true */ |
159 |
|
|
text = "is an IRC Operator"; |
160 |
|
|
sendto_one_numeric(source_p, &me, RPL_WHOISOPERATOR, target_p->name, text); |
161 |
|
|
} |
162 |
|
|
} |
163 |
|
|
} |
164 |
adx |
30 |
|
165 |
michael |
5554 |
DLINK_FOREACH(node, target_p->svstags.head) |
166 |
michael |
5551 |
{ |
167 |
michael |
5554 |
svstag = node->data; |
168 |
michael |
5551 |
|
169 |
michael |
5553 |
if (svstag->numeric == RPL_WHOISOPERATOR) |
170 |
|
|
if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)) |
171 |
|
|
continue; |
172 |
|
|
|
173 |
michael |
8481 |
if (svstag->umodes == 0 || HasUMode(source_p, svstag->umodes)) |
174 |
michael |
5551 |
sendto_one_numeric(source_p, &me, svstag->numeric | SND_EXPLICIT, "%s :%s", |
175 |
|
|
target_p->name, svstag->tag); |
176 |
|
|
} |
177 |
|
|
|
178 |
michael |
2511 |
if (HasUMode(target_p, UMODE_WEBIRC)) |
179 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISTEXT, target_p->name, |
180 |
|
|
"User connected using a webirc gateway"); |
181 |
michael |
2511 |
|
182 |
michael |
5528 |
if (HasUMode(source_p, UMODE_OPER) || source_p == target_p) |
183 |
michael |
2529 |
{ |
184 |
michael |
9419 |
char buf[UMODE_MAX_STR]; |
185 |
michael |
2529 |
char *m = buf; |
186 |
michael |
9419 |
|
187 |
michael |
2529 |
*m++ = '+'; |
188 |
michael |
5392 |
for (const struct user_modes *tab = umode_tab; tab->c; ++tab) |
189 |
michael |
5400 |
if (HasUMode(target_p, tab->flag)) |
190 |
|
|
*m++ = tab->c; |
191 |
michael |
2529 |
*m = '\0'; |
192 |
|
|
|
193 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISMODES, target_p->name, buf); |
194 |
michael |
2529 |
} |
195 |
|
|
|
196 |
michael |
5631 |
if (HasUMode(source_p, UMODE_OPER) || source_p == target_p) |
197 |
michael |
6831 |
sendto_one_numeric(source_p, &me, RPL_WHOISACTUALLY, target_p->name, |
198 |
michael |
8214 |
target_p->username, target_p->realhost, |
199 |
michael |
6831 |
target_p->sockhost); |
200 |
db |
280 |
|
201 |
michael |
9157 |
if (HasUMode(target_p, UMODE_SECURE)) |
202 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_WHOISSECURE, target_p->name); |
203 |
michael |
2246 |
|
204 |
michael |
9408 |
if (!EmptyString(target_p->tls_certfp)) |
205 |
michael |
8603 |
if (HasUMode(source_p, UMODE_OPER) || source_p == target_p) |
206 |
michael |
9408 |
sendto_one_numeric(source_p, &me, RPL_WHOISCERTFP, target_p->name, target_p->tls_certfp); |
207 |
michael |
2229 |
|
208 |
michael |
1997 |
if (MyConnect(target_p)) |
209 |
michael |
3506 |
if (!HasUMode(target_p, UMODE_HIDEIDLE) || HasUMode(source_p, UMODE_OPER) || |
210 |
|
|
source_p == target_p) |
211 |
|
|
sendto_one_numeric(source_p, &me, RPL_WHOISIDLE, target_p->name, |
212 |
michael |
5544 |
client_get_idle_time(source_p, target_p), |
213 |
michael |
8919 |
target_p->connection->created_real); |
214 |
michael |
7758 |
|
215 |
|
|
if (HasUMode(target_p, UMODE_SPY) && source_p != target_p) |
216 |
|
|
sendto_one_notice(target_p, &me, ":*** Notice -- %s (%s@%s) [%s] is doing a /whois on you", |
217 |
|
|
source_p->name, source_p->username, source_p->host, source_p->servptr->name); |
218 |
adx |
30 |
} |
219 |
michael |
1230 |
|
220 |
michael |
1997 |
/* do_whois() |
221 |
|
|
* |
222 |
|
|
* inputs - pointer to /whois source |
223 |
|
|
* - number of parameters |
224 |
|
|
* - pointer to parameters array |
225 |
|
|
* output - pointer to void |
226 |
|
|
* side effects - Does whois |
227 |
|
|
*/ |
228 |
|
|
static void |
229 |
michael |
2354 |
do_whois(struct Client *source_p, const char *name) |
230 |
michael |
1997 |
{ |
231 |
michael |
8431 |
struct Client *target_p; |
232 |
michael |
1997 |
|
233 |
michael |
6255 |
if ((target_p = hash_find_client(name)) && IsClient(target_p)) |
234 |
michael |
1997 |
whois_person(source_p, target_p); |
235 |
michael |
6255 |
else |
236 |
michael |
3109 |
sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name); |
237 |
michael |
1997 |
|
238 |
michael |
3109 |
sendto_one_numeric(source_p, &me, RPL_ENDOFWHOIS, name); |
239 |
michael |
1997 |
} |
240 |
|
|
|
241 |
michael |
3295 |
/*! \brief WHOIS command handler |
242 |
|
|
* |
243 |
|
|
* \param source_p Pointer to allocated Client struct from which the message |
244 |
|
|
* originally comes from. This can be a local or remote client. |
245 |
|
|
* \param parc Integer holding the number of supplied arguments. |
246 |
|
|
* \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL |
247 |
|
|
* pointers. |
248 |
|
|
* \note Valid arguments for this command are: |
249 |
|
|
* - parv[0] = command |
250 |
|
|
* - parv[1] = nickname/servername |
251 |
|
|
* - parv[2] = nickname |
252 |
|
|
*/ |
253 |
michael |
9077 |
static void |
254 |
michael |
3156 |
m_whois(struct Client *source_p, int parc, char *parv[]) |
255 |
michael |
1997 |
{ |
256 |
michael |
7330 |
static uintmax_t last_used = 0; |
257 |
michael |
1997 |
|
258 |
michael |
9374 |
if (EmptyString(parv[1])) |
259 |
michael |
1997 |
{ |
260 |
michael |
3109 |
sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN); |
261 |
michael |
9077 |
return; |
262 |
michael |
1997 |
} |
263 |
|
|
|
264 |
michael |
9374 |
if (!EmptyString(parv[2])) |
265 |
michael |
1997 |
{ |
266 |
|
|
/* seeing as this is going across servers, we should limit it */ |
267 |
michael |
8903 |
if ((last_used + ConfigGeneral.pace_wait_simple) > event_base->time.sec_monotonic) |
268 |
michael |
1997 |
{ |
269 |
michael |
4759 |
sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "WHOIS"); |
270 |
michael |
9077 |
return; |
271 |
michael |
1997 |
} |
272 |
|
|
|
273 |
michael |
8903 |
last_used = event_base->time.sec_monotonic; |
274 |
michael |
1997 |
|
275 |
|
|
/* |
276 |
|
|
* if we have serverhide enabled, they can either ask the clients |
277 |
michael |
4298 |
* server, or our server.. I don't see why they would need to ask |
278 |
michael |
1997 |
* anything else for info about the client.. --fl_ |
279 |
|
|
*/ |
280 |
michael |
2196 |
if (ConfigServerHide.disable_remote_commands) |
281 |
michael |
1997 |
parv[1] = parv[2]; |
282 |
|
|
|
283 |
michael |
9397 |
if (server_hunt(source_p, ":%s WHOIS %s :%s", 1, parv)->ret != HUNTED_ISME) |
284 |
michael |
9077 |
return; |
285 |
michael |
1997 |
|
286 |
|
|
parv[1] = parv[2]; |
287 |
|
|
} |
288 |
|
|
|
289 |
michael |
2354 |
do_whois(source_p, parv[1]); |
290 |
michael |
1997 |
} |
291 |
|
|
|
292 |
michael |
3295 |
/*! \brief WHOIS command handler |
293 |
|
|
* |
294 |
|
|
* \param source_p Pointer to allocated Client struct from which the message |
295 |
|
|
* originally comes from. This can be a local or remote client. |
296 |
|
|
* \param parc Integer holding the number of supplied arguments. |
297 |
|
|
* \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL |
298 |
|
|
* pointers. |
299 |
|
|
* \note Valid arguments for this command are: |
300 |
|
|
* - parv[0] = command |
301 |
|
|
* - parv[1] = nickname/servername |
302 |
|
|
* - parv[2] = nickname |
303 |
|
|
*/ |
304 |
michael |
9077 |
static void |
305 |
michael |
3156 |
mo_whois(struct Client *source_p, int parc, char *parv[]) |
306 |
michael |
1997 |
{ |
307 |
michael |
9374 |
if (EmptyString(parv[1])) |
308 |
michael |
1997 |
{ |
309 |
michael |
3109 |
sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN); |
310 |
michael |
9077 |
return; |
311 |
michael |
1997 |
} |
312 |
|
|
|
313 |
michael |
9374 |
if (!EmptyString(parv[2])) |
314 |
michael |
1997 |
{ |
315 |
michael |
9397 |
if (server_hunt(source_p, ":%s WHOIS %s :%s", 1, parv)->ret != HUNTED_ISME) |
316 |
michael |
9077 |
return; |
317 |
michael |
1997 |
|
318 |
|
|
parv[1] = parv[2]; |
319 |
|
|
} |
320 |
|
|
|
321 |
michael |
2354 |
do_whois(source_p, parv[1]); |
322 |
michael |
1997 |
} |
323 |
|
|
|
324 |
michael |
2820 |
static struct Message whois_msgtab = |
325 |
|
|
{ |
326 |
michael |
5881 |
.cmd = "WHOIS", |
327 |
michael |
9374 |
.handlers[UNREGISTERED_HANDLER] = { .handler = m_unregistered }, |
328 |
|
|
.handlers[CLIENT_HANDLER] = { .handler = m_whois }, |
329 |
|
|
.handlers[SERVER_HANDLER] = { .handler = mo_whois }, |
330 |
|
|
.handlers[ENCAP_HANDLER] = { .handler = m_ignore }, |
331 |
|
|
.handlers[OPER_HANDLER] = { .handler = mo_whois } |
332 |
michael |
1230 |
}; |
333 |
|
|
|
334 |
|
|
static void |
335 |
|
|
module_init(void) |
336 |
|
|
{ |
337 |
|
|
mod_add_cmd(&whois_msgtab); |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
static void |
341 |
|
|
module_exit(void) |
342 |
|
|
{ |
343 |
|
|
mod_del_cmd(&whois_msgtab); |
344 |
|
|
} |
345 |
|
|
|
346 |
michael |
2820 |
struct module module_entry = |
347 |
|
|
{ |
348 |
michael |
1230 |
.version = "$Revision$", |
349 |
|
|
.modinit = module_init, |
350 |
|
|
.modexit = module_exit, |
351 |
|
|
}; |