fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.git] / ircd / m_check.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_check.c
3  * Written by David Herrmann.
4  */
5
6 /*
7  * m_functions execute protocol messages on this server:
8  *
9  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
10  *            structure (with an open socket connected!). This
11  *            identifies the physical socket where the message
12  *            originated (or which caused the m_function to be
13  *            executed--some m_functions may call others...).
14  *
15  *    sptr    is the source of the message, defined by the
16  *            prefix part of the message if present. If not
17  *            or prefix not found, then sptr==cptr.
18  *
19  *            (!IsServer(cptr)) => (cptr == sptr), because
20  *            prefixes are taken *only* from servers...
21  *
22  *            (IsServer(cptr))
23  *                    (sptr == cptr) => the message didn't
24  *                    have the prefix.
25  *
26  *                    (sptr != cptr && IsServer(sptr) means
27  *                    the prefix specified servername. (?)
28  *
29  *                    (sptr != cptr && !IsServer(sptr) means
30  *                    that message originated from a remote
31  *                    user (not local).
32  *
33  *            combining
34  *
35  *            (!IsServer(sptr)) means that, sptr can safely
36  *            taken as defining the target structure of the
37  *            message in this server.
38  *
39  *    *Always* true (if 'parse' and others are working correct):
40  *
41  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
42  *
43  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
44  *            *cannot* be a local connection, unless it's
45  *            actually cptr!). [MyConnect(x) should probably
46  *            be defined as (x == x->from) --msa ]
47  *
48  *    parc    number of variable parameter strings (if zero,
49  *            parv is allowed to be NULL)
50  *
51  *    parv    a NULL terminated list of parameter pointers,
52  *
53  *                    parv[0], sender (prefix string), if not present
54  *                            this points to an empty string.
55  *                    parv[1]...parv[parc-1]
56  *                            pointers to additional parameters
57  *                    parv[parc] == NULL, *always*
58  *
59  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
60  *                    non-NULL pointers.
61  */
62 #include "config.h"
63
64 #include "channel.h"
65 #include "class.h"
66 #include "client.h"
67 #include "hash.h"
68 #include "ircd.h"
69 #include "ircd_alloc.h"
70 #include "ircd_defs.h"
71 #include "ircd_features.h"
72 #include "ircd_log.h"
73 #include "ircd_reply.h"
74 #include "ircd_snprintf.h"
75 #include "ircd_string.h"
76 #include "list.h"
77 #include "listener.h"
78 #include "match.h"
79 #include "msg.h"
80 #include "numeric.h"
81 #include "numnicks.h"
82 #include "querycmds.h"
83 #include "s_conf.h"
84 #include "s_debug.h"
85 #include "s_misc.h"
86 #include "s_user.h"
87 #include "send.h"
88 #include "sys.h"
89
90 #include <stdlib.h>
91 #include <string.h>
92 #include <arpa/inet.h>
93
94 #define COLOR_OFF '\017'
95
96 void checkChannel(struct Client *sptr, struct Channel *chptr);
97 void checkUsers(struct Client *sptr, struct Channel *chptr, int flags);
98 void checkClient(struct Client *sptr, struct Client *acptr, int flags);
99 void checkServer(struct Client *sptr, struct Client *acptr);
100
101 static int checkClones(struct Channel *chptr, char *nick, char *host) {
102     int clones = 0;
103     struct Membership *lp;
104     struct Client *acptr;
105
106     for(lp = chptr->members; lp; lp = lp->next_member) {
107         acptr = lp->user;
108         if(!strcmp(acptr->cli_user->realhost, host) && strcmp(acptr->cli_name, nick)) clones++;
109     }
110
111     return ((clones) ? clones + 1 : 0);
112 }
113
114 /* This /check implementation is based on several other ircds. All of them
115  * are licensed under the GPL.
116  * The following comments are from each implementation.
117  * --gix
118  */
119 /** ASUKA
120  * This is the implementation of the CHECK function for Asuka.
121  * Some of this code is from previous QuakeNet ircds, but most of it is mine..
122  * The old code was written by Durzel (durzel@quakenet.org).
123  *
124  * qoreQ (qoreQ@quakenet.org) - 08/14/2002
125  */
126 /** IRCPlanet
127  * Modified by falcon for ircu2.10.12-ircplanet
128  *
129  * Dominik Paulus - 2007/05/12
130  */
131 /** IRCu Patchset
132  * Modified by gix for the IRCu-Patchset.
133  *
134  * David Herrmann - 2009/03/09
135  */
136
137 #define CHECK_CHECKCHAN 0x01 /* -c */
138 #define CHECK_SHOWUSERS 0x02 /* ! -u */
139 #define CHECK_OPSONLY   0x04 /* -o */
140 #define CHECK_SHOWIPS   0x08 /* -i */
141
142 /*
143  * Syntax: CHECK <channel|nick|server> [-flags]
144  *
145  * Where valid flags are:
146  * -c: Show channels when checking a user even if the user is on more than 50 channels.
147  * -i: Show IPs instead of hostnames when displaying results.
148  * -o: Only show channel operators when checking a channel.
149  * -u: Hide users when checking a channel. Overrides -o.
150  */
151 /*
152  * m_check()
153  * generic message handler
154  */
155 int mo_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
156     struct Channel *chptr;
157     struct Client *acptr;
158     int i, flags = CHECK_SHOWUSERS;
159
160     if(!IsXtraOp(sptr))
161         return send_reply(sptr, ERR_NOPRIVILEGES);
162
163     if(parc < 2)
164         return send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
165
166     /* This checks to see if any flags have been supplied */
167     if((parc > 2) && (parv[2][0] == '-')) {
168         for(i = 1; parv[2][i]; ++i) {
169             switch (parv[2][i]) {
170                 case 'c':
171                     flags |= CHECK_CHECKCHAN;
172                     break;
173                 case 'o':
174                     if(flags & CHECK_SHOWUSERS)
175                         flags |= CHECK_OPSONLY;
176                     break;
177                 case 'u':
178                     flags &= ~(CHECK_SHOWUSERS | CHECK_OPSONLY);
179                     break;
180                 case 'i':
181                     flags |= CHECK_SHOWIPS;
182                     break;
183             }
184         }
185     }
186
187     if((chptr = FindChannel(parv[1]))) {
188         checkChannel(sptr, chptr);
189         checkUsers(sptr, chptr, flags);
190     }
191     else if((acptr = FindUser(parv[1]))) {
192         if(!IsRegistered(acptr))
193             return send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
194         checkClient(sptr, acptr, flags);
195     }
196     else if((acptr = FindServer(parv[1])))
197         checkServer(sptr, acptr);
198     else send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
199
200     return 1;
201 }
202
203 void checkServer(struct Client *sptr, struct Client *acptr) {
204     char outbuf[BUFSIZE];
205     int dlinkc = 0;
206     struct DLink* slink = NULL;
207
208     /* Header */
209     send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
210     send_reply(sptr, RPL_DATASTR, " ");
211
212     ircd_snprintf(0, outbuf, sizeof(outbuf), "   Connected at: %s", myctime(acptr->cli_serv->timestamp));
213     send_reply(sptr, RPL_DATASTR, outbuf);
214
215     ircd_snprintf(0, outbuf, sizeof(outbuf), "    Server name: %s", acptr->cli_name);
216     send_reply(sptr, RPL_DATASTR,  outbuf);
217
218     ircd_snprintf(0, outbuf, sizeof(outbuf), "        Numeric: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
219     send_reply(sptr, RPL_DATASTR, outbuf);
220
221     ircd_snprintf(0, outbuf, sizeof(outbuf), "          Users: %d / %d", cli_serv(acptr)->clients, base64toint(cli_serv(acptr)->nn_capacity));
222     send_reply(sptr, RPL_DATASTR, outbuf);
223
224     if(IsBurst(acptr))
225         send_reply(sptr, RPL_DATASTR, "         Status: Bursting");
226     if(IsBurstAck(acptr))
227         send_reply(sptr, RPL_DATASTR, "         Status: Awaiting EOB Ack");
228     if(IsService(acptr))
229         send_reply(sptr, RPL_DATASTR, "         Status: Network Service");
230     if(IsHub(acptr))
231         send_reply(sptr, RPL_DATASTR, "         Status: Network Hub");
232     else
233         send_reply(sptr, RPL_DATASTR, "         Status: Network Leaf");
234
235     send_reply(sptr, RPL_DATASTR, " ");
236     send_reply(sptr, RPL_DATASTR, "Downlinks:");
237     for(slink = cli_serv(acptr)->down; slink; slink = slink->next) {
238         ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc,
239                       IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" :
240                       IsService(slink->value.cptr) ? "=" :IsHub(slink->value.cptr) ? "+" : " ",
241                       cli_name(slink->value.cptr));
242         send_reply(sptr, RPL_DATASTR, outbuf);
243     }
244     if(!dlinkc)
245         send_reply(sptr, RPL_DATASTR, "<none>");
246
247     /* Send 'END OF CHECK' message */
248     send_reply(sptr, RPL_ENDOFCHECK, " ");
249 }
250
251 void checkClient(struct Client *sptr, struct Client *acptr, int flags) {
252     struct Channel *chptr;
253     struct Membership *lp;
254     char outbuf[BUFSIZE], *ptr;
255     time_t nowr;
256
257     /* Header */
258     send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
259     send_reply(sptr, RPL_DATASTR, " ");
260
261     ircd_snprintf(0, outbuf, sizeof(outbuf), "            Nick: %s (%s%s)", acptr->cli_name, NumNick(acptr));
262     send_reply(sptr, RPL_DATASTR, outbuf);
263
264     ircd_snprintf(0, outbuf, sizeof(outbuf), "       Signed on: %s", MyUser(acptr)?myctime(acptr->cli_firsttime):"<unknown>");
265     send_reply(sptr, RPL_DATASTR, outbuf);
266
267     ircd_snprintf(0, outbuf, sizeof(outbuf), "       Timestamp: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
268     send_reply(sptr, RPL_DATASTR, outbuf);
269
270     ircd_snprintf(0, outbuf, sizeof(outbuf), "           Ident: %s", acptr->cli_user->username);
271     send_reply(sptr, RPL_DATASTR, outbuf);
272
273     ircd_snprintf(0, outbuf, sizeof(outbuf), "Current Hostmask: %s", acptr->cli_user->host);
274     send_reply(sptr, RPL_DATASTR, outbuf);
275
276     ircd_snprintf(0, outbuf, sizeof(outbuf), "       Real Host: %s (%s)", acptr->cli_user->realhost, ircd_ntoa(&(cli_ip(acptr))));
277     send_reply(sptr, RPL_DATASTR, outbuf);
278
279     if(IsAccount(acptr)) {
280         ircd_snprintf(0, outbuf, sizeof(outbuf), "         Account: %s (%s)", acptr->cli_user->account, acptr->cli_user->acc_create?myctime(acptr->cli_user->acc_create):"0");
281         send_reply(sptr, RPL_DATASTR, outbuf);
282     }
283
284     if(IsFakeHost(acptr)) {
285         ircd_snprintf(0, outbuf, sizeof(outbuf), "       Fake Host: %s%c", acptr->cli_user->fakehost, COLOR_OFF);
286         send_reply(sptr, RPL_DATASTR, outbuf);
287     }
288
289     ircd_snprintf(0, outbuf, sizeof(outbuf), "       Real Name: %s%c", cli_info(acptr), COLOR_OFF);
290     send_reply(sptr, RPL_DATASTR, outbuf);
291
292     if(IsAnOper(acptr))
293         send_reply(sptr, RPL_DATASTR, "          Status: IRC Operator");
294
295     ircd_snprintf(0, outbuf, sizeof(outbuf), "    Connected to: %s", cli_name(acptr->cli_user->server));
296     send_reply(sptr, RPL_DATASTR, outbuf);
297
298     ptr = umode_str(acptr);
299     if(strlen(ptr) < 1)
300         strcpy(outbuf, "        Umode(s): <none>");
301     else
302         ircd_snprintf(0, outbuf, sizeof(outbuf), "        Umode(s): +%s", ptr);
303     send_reply(sptr, RPL_DATASTR, outbuf);
304
305     if(acptr->cli_user->joined == 0)
306         send_reply(sptr, RPL_DATASTR, "      Channel(s): <none>");
307     else if(!(flags & CHECK_CHECKCHAN) && acptr->cli_user->joined > 50) {
308         /* NB. As a sanity check, we DO NOT show the individual channels the
309          *     client is on if it is on > 50 channels.  This is to prevent the ircd
310          *     barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
311          *     an Oper would want to see every single channel 'x' client is on anyway if
312          *     they are on *that* many).
313          */
314         ircd_snprintf(0, outbuf, sizeof(outbuf), "      Channel(s): - (total: %u)", acptr->cli_user->joined);
315         send_reply(sptr, RPL_DATASTR, outbuf);
316     }
317     else {
318         char chntext[BUFSIZE];
319         int len = strlen("      Channel(s): ");
320         int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
321         *chntext = '\0';
322
323         strcpy(chntext, "      Channel(s): ");
324         for(lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
325             chptr = lp->channel;
326             if(len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
327                 send_reply(sptr, RPL_DATASTR, chntext);
328                 *chntext = '\0';
329                 strcpy(chntext, "      Channel(s): ");
330                 len = strlen(chntext);
331             }
332             if(IsDeaf(acptr))
333                 *(chntext + len++) = '-';
334             if(is_chan_op(acptr, chptr))
335                 *(chntext + len++) = '@';
336             else if(has_voice(acptr, chptr))
337                 *(chntext + len++) = '+';
338             else if(IsZombie(lp))
339                 *(chntext + len++) = '!';
340             if(len)
341                 *(chntext + len) = '\0';
342
343             strcpy(chntext + len, chptr->chname);
344             len += strlen(chptr->chname);
345             strcat(chntext + len, " ");
346             len++;
347         }
348
349         if(chntext[0] != '\0')
350             send_reply(sptr, RPL_DATASTR, chntext);
351     }
352
353     /* If client processing command ISN'T target (or a registered
354      * Network Service), show idle time since the last time we
355      * parsed something.
356      */
357     if(MyUser(acptr)) {
358         nowr = CurrentTime - acptr->cli_user->last;
359         ircd_snprintf(0, outbuf, sizeof(outbuf), "        Idle for: %d days, %02ld:%02ld:%02ld",
360             nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
361         send_reply(sptr, RPL_DATASTR, outbuf);
362     }
363
364     /* Away message (if applicable) */
365     if(acptr->cli_user->away) {
366         ircd_snprintf(0, outbuf, sizeof(outbuf), "    Away message: %s", acptr->cli_user->away);
367         send_reply(sptr, RPL_DATASTR, outbuf);
368     }
369
370     /* If local user.. */
371     if(MyUser(acptr)) {
372         send_reply(sptr, RPL_DATASTR, " ");
373         ircd_snprintf(0, outbuf, sizeof(outbuf), "            Port: %d", cli_listener(acptr)->addr.port);
374         send_reply(sptr, RPL_DATASTR, outbuf);
375         ircd_snprintf(0, outbuf, sizeof(outbuf), "       Data sent: %0.3u bytes", cli_receiveB(acptr));
376         send_reply(sptr, RPL_DATASTR, outbuf);
377         ircd_snprintf(0, outbuf, sizeof(outbuf), "   Data received: %0.3u bytes", cli_sendB(acptr));
378         send_reply(sptr, RPL_DATASTR, outbuf);
379         ircd_snprintf(0, outbuf, sizeof(outbuf), "   receiveQ size: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
380         send_reply(sptr, RPL_DATASTR, outbuf);
381         ircd_snprintf(0, outbuf, sizeof(outbuf), "      sendQ size: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));
382         send_reply(sptr, RPL_DATASTR, outbuf);
383     }
384
385     send_reply(sptr, RPL_ENDOFCHECK, " ");
386 }
387
388 void checkChannel(struct Client *sptr, struct Channel *chptr) {
389     char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
390
391     /* Header */
392     send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
393     send_reply(sptr, RPL_DATASTR, " ");
394
395     /* Creation Time */
396     ircd_snprintf(sptr, outbuf, sizeof(outbuf), "  Creation time: %s", myctime(chptr->creationtime));
397     send_reply(sptr, RPL_DATASTR, outbuf);
398
399     /* Topic */
400     if(strlen(chptr->topic) <= 0)
401         send_reply(sptr, RPL_DATASTR, "          Topic: <none>");
402     else {
403         ircd_snprintf(sptr, outbuf, sizeof(outbuf), "          Topic: %s", chptr->topic);
404         send_reply(sptr, RPL_DATASTR, outbuf);
405         ircd_snprintf(sptr, outbuf, sizeof(outbuf), "         Set by: %s", chptr->topic_nick);
406         send_reply(sptr, RPL_DATASTR, outbuf);
407     }
408
409     strcpy(outbuf, "Channel mode(s): ");
410
411     modebuf[0] = '\0';
412     parabuf[0] = '\0';
413     channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, 0);
414
415     if(modebuf[1] == '\0')
416         strcat(outbuf, "<none>");
417     else if(*parabuf) {
418         strcat(outbuf, modebuf);
419         strcat(outbuf, " ");
420         strcat(outbuf, parabuf);
421     }
422     else
423         strcat(outbuf, modebuf);
424
425     send_reply(sptr, RPL_DATASTR, outbuf);
426     /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
427 }
428
429 void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
430     struct Membership *lp;
431     struct Ban *channelban;
432     struct Client *acptr;
433
434     char outbuf[BUFSIZE], ustat[64];
435     int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, c = 0, authed = 0;
436
437     if(flags & CHECK_SHOWUSERS) send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
438
439     for(lp = chptr->members; lp; lp = lp->next_member) {
440         int opped = 0;
441
442         acptr = lp->user;
443         if((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0) {
444             ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c);
445             clones++;
446         }
447         else
448             strcpy(ustat, "   ");
449
450         if(chptr && is_chan_op(acptr, chptr)) {
451             strcat(ustat, "@");
452             opcntr++;
453             opped = 1;
454         }
455         else if(chptr && has_voice(acptr, chptr)) {
456             strcat(ustat, "+");
457             vcntr++;
458         }
459         else
460             strcat(ustat, " ");
461
462         if((c = IsAccount(acptr)) != 0) ++authed;
463         if((flags & CHECK_SHOWUSERS) && (!(flags & CHECK_OPSONLY) || opped)) {
464             ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
465             send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, acptr->cli_user->username,
466                        (flags & CHECK_SHOWIPS) ? ircd_ntoa(&cli_ip(acptr)) : acptr->cli_user->realhost, outbuf, 
467                        (c ? acptr->cli_user->account : ""));
468         }
469
470         cntr++;
471     }
472
473     ircd_snprintf(0, outbuf, sizeof(outbuf), "Total users: %d (%d ops, %d voiced, %d clones, %d authed)",
474                   cntr, opcntr, vcntr, clones, authed);
475     send_reply(sptr, RPL_DATASTR, outbuf);
476
477     /* Do not display bans if ! flags & CHECK_SHOWUSERS */
478     if(!(flags & CHECK_SHOWUSERS)) {
479         send_reply(sptr, RPL_ENDOFCHECK, " ");
480         return;
481     }
482
483     send_reply(sptr, RPL_DATASTR, " ");
484     /* Bans */
485     send_reply(sptr, RPL_DATASTR, "Bans/Exceptions on channel:");
486
487     for(channelban = chptr->banlist; channelban; channelban = channelban->next) {
488         ircd_snprintf(0, outbuf, sizeof(outbuf),  "%c [%d] - %s - Set by %s, on %s", (channelban->flags & BAN_EXCEPTION)?'e':'b',
489                       ++bans, channelban->banstr, channelban->who, myctime(channelban->when));
490         send_reply(sptr, RPL_DATASTR, outbuf);
491     }
492
493     if(bans == 0)
494         send_reply(sptr, RPL_DATASTR, "<none>");
495
496     send_reply(sptr, RPL_ENDOFCHECK, " ");
497 }
498