fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.git] / ircd / numnicks.c
1 /*
2  * IRC - Internet Relay Chat, ircd/channel.c
3  * Copyright (C) 1996 Carlo Wood (I wish this was C++ - this sucks :/)
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 2, 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 /** @file
20  * @brief Implementation of numeric nickname operations.
21  * @version $Id: numnicks.c 1398 2005-05-08 00:56:05Z entrope $
22  */
23 #include "config.h"
24
25 #include "numnicks.h"
26 #include "client.h"
27 #include "ircd.h"
28 #include "ircd_alloc.h"
29 #include "ircd_log.h"
30 #include "ircd_string.h"
31 #include "match.h"
32 #include "s_bsd.h"
33 #include "s_debug.h"
34 #include "s_misc.h"
35 #include "struct.h"
36
37 /* #include <assert.h> -- Now using assert in ircd_log.h */
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42
43 /** @page numnicks Numeric Nicks
44  * %Numeric nicks (numnicks) are new as of version ircu2.10.00beta1.
45  *
46  * The idea is as follows:
47  * In most messages (for protocol 10+) the original nick will be
48  * replaced by a 5 character string: YYXXX
49  * Where 'YY' represents the server, and 'XXX' the nick on that server.
50  *
51  * 'YYXXX' should not interfere with the input parser, and therefore is
52  * not allowed to contain spaces or a ':'.
53  * Also, 'YY' can't start with a '+' because of m_server().
54  *
55  * We keep the characters printable for debugging reasons too.
56  *
57  * The 'XXX' value can be larger then the maximum number of clients
58  * per server, we use a mask (Server::nn_mask) to get the real
59  * client numeric. The overhead is used to have some redundancy so
60  * just-disconnected-client aren't confused with just-connected ones.
61  */
62
63
64 /* These must be the same on ALL servers ! Do not change ! */
65
66 /** Number of bits encoded in one numnick character. */
67 #define NUMNICKLOG 6
68 /** Bitmask to select value of next numnick character. */
69 #define NUMNICKMASK 63          /* (NUMNICKBASE-1) */
70 /** Number of servers representable in a numnick. */
71 #define NN_MAX_SERVER 4096      /* (NUMNICKBASE * NUMNICKBASE) */
72 /** Number of clients representable in a numnick. */
73 #define NN_MAX_CLIENT 262144    /* NUMNICKBASE ^ 3 */
74
75 /*
76  * The internal counter for the 'XX' of local clients
77  */
78 /** Maximum used server numnick, plus one. */
79 static unsigned int lastNNServer = 0;
80 /** Array of servers indexed by numnick. */
81 static struct Client* server_list[NN_MAX_SERVER];
82
83 /* *INDENT-OFF* */
84
85 /**
86  * Converts a numeric to the corresponding character.
87  * The following characters are currently known to be forbidden:
88  *
89  * '\\0' : Because we use '\\0' as end of line.
90  *
91  * ' '  : Because parse_*() uses this as parameter separator.
92  *
93  * ':'  : Because parse_server() uses this to detect if a prefix is a
94  *        numeric or a name.
95  *
96  * '+'  : Because m_nick() uses this to determine if parv[6] is a
97  *        umode or not.
98  *
99  * '&', '#', '$', '@' and '%' :
100  *        Because m_message() matches these characters to detect special cases.
101  */
102 static const char convert2y[] = {
103   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
104   'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
105   'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
106   'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
107 };
108
109 /** Converts a character to its (base64) numnick value. */
110 static const unsigned int convert2n[] = {
111    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114   52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
115    0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
116   15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
117    0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
118   41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0,
119
120    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
128 };
129
130 /* *INDENT-ON* */
131
132 /** Convert a string to its value as a numnick.
133  * @param[in] s Numnick string to decode.
134  * @return %Numeric nickname value.
135  */
136 unsigned int base64toint(const char* s)
137 {
138   unsigned int i = convert2n[(unsigned char) *s++];
139   while (*s) {
140     i <<= NUMNICKLOG;
141     i += convert2n[(unsigned char) *s++];
142   }
143   return i;
144 }
145
146 /** Encode a number as a numnick.
147  * @param[out] buf Output buffer.
148  * @param[in] v Value to encode.
149  * @param[in] count Number of numnick digits to write to \a buf.
150  */
151 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
152 {
153   buf[count] = '\0';
154   while (count > 0) {
155     buf[--count] = convert2y[(v & NUMNICKMASK)];
156     v >>= NUMNICKLOG;
157   }
158   return buf;
159 }
160
161 /** Look up a server by numnick string.
162  * See @ref numnicks for more details.
163  * @param[in] numeric %Numeric nickname of server (may contain trailing junk).
164  * @return %Server with that numnick (or NULL).
165  */
166 static struct Client* FindXNServer(const char* numeric)
167 {
168   char buf[3];
169   buf[0] = *numeric++;
170   buf[1] = *numeric;
171   buf[2] = '\0';
172   Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
173   return server_list[base64toint(buf)];
174 }
175
176 /** Look up a server by numnick string.
177  * See @ref numnicks for more details.
178  * @param[in] numeric %Numeric nickname of server.
179  * @return %Server with that numnick (or NULL).
180  */
181 struct Client* FindNServer(const char* numeric)
182 {
183   unsigned int len = strlen(numeric);
184
185   if (len < 3) {
186     Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
187     return server_list[base64toint(numeric)];
188   }
189   else if (len == 3) {
190     Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, 
191            convert2n[(unsigned char) *numeric]));
192     return server_list[convert2n[(unsigned char) *numeric]];
193   }
194   return FindXNServer(numeric);
195 }
196
197 /** Look up a user by numnick string.
198  * See @ref numnicks for more details.
199  * @param[in] yxx %Numeric nickname of user.
200  * @return %User with that numnick (or NULL).
201  */
202 struct Client* findNUser(const char* yxx)
203 {
204   struct Client* server = 0;
205   if (5 == strlen(yxx)) {
206     if (0 != (server = FindXNServer(yxx))) {
207       Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx, 
208              base64toint(yxx + 2) & cli_serv(server)->nn_mask));
209       return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
210     }
211   }
212   else if (0 != (server = FindNServer(yxx))) {
213     Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
214            yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
215     return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
216   }
217   return 0;
218 }
219
220 /** Remove a client from a server's user array.
221  * @param[in] server %Server that owns the user to remove.
222  * @param[in] yxx Numnick of client to remove.
223  */
224 void RemoveYXXClient(struct Client* server, const char* yxx)
225 {
226   assert(0 != server);
227   assert(0 != yxx);
228   if (*yxx) {
229     Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
230            base64toint(yxx) & cli_serv(server)->nn_mask));
231     cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
232   }
233 }
234
235 /** Set a server's numeric nick.
236  * @param[in] cptr %Client that announced the server (ignored).
237  * @param[in,out] server %Server that is being assigned a numnick.
238  * @param[in] yxx %Numeric nickname for server.
239  */
240 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
241 {
242   unsigned int index;
243   if (5 == strlen(yxx)) {
244     ircd_strncpy(cli_yxx(server), yxx, 2);
245     ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
246   }
247   else {
248     (cli_yxx(server))[0]               = yxx[0];
249     cli_serv(server)->nn_capacity[0] = yxx[1];
250     cli_serv(server)->nn_capacity[1] = yxx[2];
251   }
252   cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);
253
254   index = base64toint(cli_yxx(server));
255   if (index >= lastNNServer)
256     lastNNServer = index + 1;
257   server_list[index] = server;
258
259   /* Note, exit_one_client uses the fact that `client_list' != NULL to
260    * determine that SetServerYXX has been called - and then calls
261    * ClearServerYXX. However, freeing the allocation happens in free_client() */
262   cli_serv(server)->client_list =
263       (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
264 }
265
266 /** Set a server's capacity.
267  * @param[in] c %Server whose capacity is being set.
268  * @param[in] capacity Maximum number of clients the server supports.
269  */
270 void SetYXXCapacity(struct Client* c, unsigned int capacity)
271 {
272   unsigned int max_clients = 16;
273   /*
274    * Calculate mask to be used for the maximum number of clients
275    */
276   while (max_clients < capacity)
277     max_clients <<= 1;
278   /*
279    * Sanity checks
280    */
281   if (max_clients > NN_MAX_CLIENT) {
282     fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
283             "too large ! Please decrease this value.\n",
284              max_clients - NN_MAX_CLIENT);
285     exit(-1);
286   }
287   --max_clients;
288   inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
289   cli_serv(c)->nn_mask = max_clients;       /* Our Numeric Nick mask */
290   cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
291                                                      sizeof(struct Client*));
292   server_list[base64toint(cli_yxx(c))] = c;
293 }
294
295 /** Set a server's numeric nick.
296  * See @ref numnicks for more details.
297  * @param[in] c %Server that is being assigned a numnick.
298  * @param[in] numeric Numnick value for server.
299  */
300 void SetYXXServerName(struct Client* c, unsigned int numeric)
301 {
302   assert(0 != c);
303   assert(numeric < NN_MAX_SERVER);
304
305   inttobase64(cli_yxx(c), numeric, 2);
306   if (numeric >= lastNNServer)
307     lastNNServer = numeric + 1;
308   server_list[numeric] = c;
309 }
310
311 /** Unassign a server's numnick.
312  * @param[in] server %Server that should be removed from the numnick table.
313  */
314 void ClearServerYXX(const struct Client *server)
315 {
316   unsigned int index = base64toint(cli_yxx(server));
317   if (server_list[index] == server)     /* Sanity check */
318     server_list[index] = 0;
319 }
320
321 /** Register numeric of new (remote) client.
322  * See @ref numnicks for more details.
323  * Add it to the appropriate client_list.
324  * @param[in] acptr %User being registered.
325  * @param[in] yxx User's numnick.
326  */
327 void SetRemoteNumNick(struct Client* acptr, const char *yxx)
328 {
329   struct Client** acptrp;
330   struct Client*  server = cli_user(acptr)->server;
331
332   if (5 == strlen(yxx)) {
333     strcpy(cli_yxx(acptr), yxx + 2);
334   }
335   else {
336     (cli_yxx(acptr))[0] = *++yxx;
337     (cli_yxx(acptr))[1] = *++yxx;
338     (cli_yxx(acptr))[2] = 0;
339   }
340   Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
341          base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));
342
343   acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
344   if (*acptrp) {
345     /*
346      * this exits the old client in the array, not the client
347      * that is being set
348      */
349     exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
350   }
351   *acptrp = acptr;
352 }
353
354
355 /** Register numeric of new (local) client.
356  * See @ref numnicks for more details.
357  * Assign a numnick and add it to our client_list.
358  * @param[in] cptr %User being registered.
359  */
360 int SetLocalNumNick(struct Client *cptr)
361 {
362   static unsigned int last_nn     = 0;
363   struct Client**     client_list = cli_serv(&me)->client_list;
364   unsigned int        mask        = cli_serv(&me)->nn_mask;
365   unsigned int        count       = 0;
366
367   assert(cli_user(cptr)->server == &me);
368
369   while (client_list[last_nn & mask]) {
370     if (++count == NN_MAX_CLIENT) {
371       assert(count < NN_MAX_CLIENT);
372       return 0;
373     }
374     if (++last_nn == NN_MAX_CLIENT)
375       last_nn = 0;
376   }
377   client_list[last_nn & mask] = cptr;  /* Reserve the numeric ! */
378
379   inttobase64(cli_yxx(cptr), last_nn, 3);
380   if (++last_nn == NN_MAX_CLIENT)
381     last_nn = 0;
382   return 1;
383 }
384
385 /** Mark servers whose name matches the given (compiled) mask by
386  * setting their FLAG_MAP flag.
387  * @param[in] cmask Compiled mask for server names.
388  * @param[in] minlen Minimum match length for \a cmask.
389  * @return Number of servers marked.
390  */
391 int markMatchexServer(const char *cmask, int minlen)
392 {
393   int cnt = 0;
394   int i;
395   struct Client *acptr;
396
397   for (i = 0; i < lastNNServer; i++) {
398     if ((acptr = server_list[i]))
399     {
400       if (matchexec(cli_name(acptr), cmask, minlen))
401         ClrFlag(acptr, FLAG_MAP);
402       else
403       {
404         SetFlag(acptr, FLAG_MAP);
405         cnt++;
406       }
407     }
408   }
409   return cnt;
410 }
411
412 /** Find first server whose name matches the given mask.
413  * @param[in,out] mask %Server name mask (collapse()d in-place).
414  * @return Matching server with lowest numnick value (or NULL).
415  */
416 struct Client* find_match_server(char *mask)
417 {
418   struct Client *acptr;
419   int i;
420
421   if (!(BadPtr(mask))) {
422     collapse(mask);
423     for (i = 0; i < lastNNServer; i++) {
424       if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr))))
425         return acptr;
426     }
427   }
428   return 0;
429 }
430
431 /** Encode an IP address in the base64 used by numnicks.
432  * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6
433  * addresses), the 32-bit host address is encoded directly as six
434  * characters.
435  *
436  * For IPv6 addresses, each 16-bit address segment is encoded as three
437  * characters, but the longest run of zero segments is encoded using an
438  * underscore.
439  * @param[out] buf Output buffer to write to.
440  * @param[in] addr IP address to encode.
441  * @param[in] count Number of bytes writable to \a buf.
442  * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses.
443  */
444 const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok)
445 {
446   if (irc_in_addr_is_ipv4(addr)) {
447     assert(count >= 6);
448     inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6);
449   } else if (!v6_ok) {
450     assert(count >= 6);
451     if (addr->in6_16[0] == htons(0x2002))
452         inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6);
453     else
454         strcpy(buf, "AAAAAA");
455   } else {
456     unsigned int max_start, max_zeros, curr_zeros, zero, ii;
457     char *output = buf;
458
459     assert(count >= 25);
460     /* Can start by printing out the leading non-zero parts. */
461     for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) {
462       inttobase64(output, ntohs(addr->in6_16[ii]), 3);
463       output += 3;
464     }
465     /* Find the longest run of zeros. */
466     for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
467       if (!addr->in6_16[ii])
468         curr_zeros++;
469       else if (curr_zeros > max_zeros) {
470         max_start = ii - curr_zeros;
471         max_zeros = curr_zeros;
472         curr_zeros = 0;
473       }
474     }
475     if (curr_zeros > max_zeros) {
476       max_start = ii - curr_zeros;
477       max_zeros = curr_zeros;
478       curr_zeros = 0;
479     }
480     /* Print the rest of the address */
481     for (ii = zero; ii < 8; ) {
482       if ((ii == max_start) && max_zeros) {
483         *output++ = '_';
484         ii += max_zeros;
485       } else {
486         inttobase64(output, ntohs(addr->in6_16[ii]), 3);
487         output += 3;
488         ii++;
489       }
490     }
491     *output = '\0';
492   }
493   return buf;
494 }
495
496 /** Decode an IP address from base64.
497  * @param[in] input Input buffer to decode.
498  * @param[out] addr IP address structure to populate.
499  */
500 void base64toip(const char* input, struct irc_in_addr* addr)
501 {
502   memset(addr, 0, sizeof(*addr));
503   if (strlen(input) == 6) {
504     unsigned int in = base64toint(input);
505     /* An all-zero address should stay that way. */
506     if (in) {
507       addr->in6_16[5] = htons(65535);
508       addr->in6_16[6] = htons(in >> 16);
509       addr->in6_16[7] = htons(in & 65535);
510     }
511   } else {
512     unsigned int pos = 0;
513     do {
514       if (*input == '_') {
515         unsigned int left;
516         for (left = (25 - strlen(input)) / 3 - pos; left; left--)
517           addr->in6_16[pos++] = 0;
518         input++;
519       } else {
520         unsigned short accum = convert2n[(unsigned char)*input++];
521         accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
522         accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
523         addr->in6_16[pos++] = ntohs(accum);
524       }
525     } while (pos < 8);
526   }
527 }