Add option to debug Client block selections. Fix related buglet in
[ircu2.10.12-pk.git] / ircd / ircd_string.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_string.c
3  * Copyright (C) 1999 Thomas Helvey
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 /** @file
20  * @brief Implementation of string operations.
21  * @version $Id$
22  */
23 #include "config.h"
24
25 #include "ircd_string.h"
26 #include "ircd_defs.h"
27 #include "ircd_chattr.h"
28 #include "ircd_log.h"
29 #include "res.h"
30
31 /* #include <assert.h> -- Now using assert in ircd_log.h */
32 #include <string.h>
33 #include <regex.h>
34 #include <sys/types.h>
35 #include <netinet/in.h>
36
37 /*
38  * include the character attribute tables here
39  */
40 #include "chattr.tab.c"
41
42
43 /*
44  * Disallow a hostname label to contain anything but a [-a-zA-Z0-9].
45  * It may not start or end on a '.'.
46  * A label may not end on a '-', the maximum length of a label is
47  * 63 characters.
48  * On top of that (which seems to be the RFC) we demand that the
49  * top domain does not contain any digits.
50  */
51 /** Regular expression to match a hostname.
52  * Matches zero or more alphanumeric labels followed by '.' and a
53  * final label that may only contain alphabetic characters.
54  */
55 static const char* hostExpr = "^([-0-9A-Za-z]*[0-9A-Za-z]\\.)+[A-Za-z]+$";
56 /** Compiled regex to match a hostname.  Built from #hostExpr. */
57 static regex_t hostRegex;
58
59 /** Regular expression to match an IP address. */
60 static const char* addrExpr =
61     "^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){1,3}"
62     "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$";
63 /** Compiled regex to match an IP address.  Built from #addrExpr. */
64 static regex_t addrRegex;
65
66 /** Initialize the string matching code. */
67 int init_string(void)
68 {
69   /*
70    * initialize matching expressions
71    * XXX - expressions MUST be correct, don't change expressions
72    * without testing them. Might be a good idea to exit if these fail,
73    * important code depends on them.
74    * TODO: use regerror for an error message
75    */
76   if (regcomp(&hostRegex, hostExpr, REG_EXTENDED | REG_NOSUB))
77     return 0;
78
79   if (regcomp(&addrRegex, addrExpr, REG_EXTENDED | REG_NOSUB))
80     return 0;
81   return 1;
82 }
83
84 /** Check whether \a str looks like a hostname.
85  * @param[in] str String that might be a hostname.
86  * @return Non-zero if it conforms to the rules, zero if not.
87  */
88 int string_is_hostname(const char* str)
89 {
90   assert(0 != str);
91   return (strlen(str) <= HOSTLEN && 0 == regexec(&hostRegex, str, 0, 0, 0));
92 }
93
94 /** Check whether \a str looks like an IP address.
95  * @param[in] str String that might be an address.
96  * @return Non-zero if it conforms to the rules, zero if not.
97  */
98 int string_is_address(const char* str)
99 {
100   assert(0 != str);
101   return (0 == regexec(&addrRegex, str, 0, 0, 0));
102 }
103
104 /** Check whether \a str contains wildcard characters.
105  * @param[in] str String that might contain wildcards.
106  * @return Non-zero if \a str contains naked (non-escaped) wildcards,
107  * zero if there are none or if they are all escaped.
108  */
109 int string_has_wildcards(const char* str)
110 {
111   assert(0 != str);
112   for ( ; *str; ++str) {
113     if ('\\' == *str) {
114       if ('\0' == *++str)
115         break;
116     }
117     else if ('*' == *str || '?' == *str)
118       return 1;
119   }
120   return 0;
121 }
122
123 /** Split a string on certain delimiters.
124  * This is a reentrant version of normal strtok().  The first call for
125  * a particular input string must use a non-NULL \a str; *save will be
126  * initialized based on that.  Later calls must use a NULL \a str;
127  * *save will be updated.
128  * @param[in,out] save Pointer to a position indicator.
129  * @param[in] str Pointer to the input string, or NULL to continue.
130  * @param[in] fs String that lists token delimiters.
131  * @return Next token in input string, or NULL if no tokens remain.
132  */
133 char* ircd_strtok(char **save, char *str, char *fs)
134 {
135   char *pos = *save;            /* keep last position across calls */
136   char *tmp;
137
138   if (str)
139     pos = str;                  /* new string scan */
140
141   while (pos && *pos && strchr(fs, *pos) != NULL)
142     pos++;                      /* skip leading separators */
143
144   if (!pos || !*pos)
145     return (pos = *save = NULL);        /* string contains only sep's */
146
147   tmp = pos;                    /* now, keep position of the token */
148
149   while (*pos && strchr(fs, *pos) == NULL)
150     pos++;                      /* skip content of the token */
151
152   if (*pos)
153     *pos++ = '\0';              /* remove first sep after the token */
154   else
155     pos = NULL;                 /* end of string */
156
157   *save = pos;
158   return (tmp);
159 }
160
161 /** Rewrite a comma-delimited list of items to remove duplicates.
162  * @param[in,out] buffer Comma-delimited list.
163  * @return The input buffer \a buffer.
164  */
165 char* canonize(char* buffer)
166 {
167   static char cbuf[BUFSIZE];
168   char*       s;
169   char*       t;
170   char*       cp = cbuf;
171   int         l = 0;
172   char*       p = NULL;
173   char*       p2;
174
175   *cp = '\0';
176
177   for (s = ircd_strtok(&p, buffer, ","); s; s = ircd_strtok(&p, NULL, ","))
178   {
179     if (l)
180     {
181       p2 = NULL;
182       for (t = ircd_strtok(&p2, cbuf, ","); t; t = ircd_strtok(&p2, NULL, ","))
183         if (0 == ircd_strcmp(s, t))
184           break;
185         else if (p2)
186           p2[-1] = ',';
187     }
188     else
189       t = NULL;
190     if (!t)
191     {
192       if (l)
193         *(cp - 1) = ',';
194       else
195         l = 1;
196       strcpy(cp, s);
197       if (p)
198         cp += (p - s);
199     }
200     else if (p2)
201       p2[-1] = ',';
202   }
203   return cbuf;
204 }
205
206 /** Copy one string to another, not to exceed a certain length.
207  * @param[in] s1 Output buffer.
208  * @param[in] s2 Source buffer.
209  * @param[in] n Maximum number of bytes to write, plus one.
210  * @return The original input buffer \a s1.
211  */
212 char* ircd_strncpy(char* s1, const char* s2, size_t n)
213 {
214   char* endp = s1 + n;
215   char* s = s1;
216
217   assert(0 != s1);
218   assert(0 != s2);
219
220   while (s < endp && (*s++ = *s2++))
221     ;
222   return s1;
223 }
224
225
226 #ifndef FORCEINLINE
227 NTL_HDR_strChattr { NTL_SRC_strChattr }
228 NTL_HDR_strCasediff { NTL_SRC_strCasediff }
229 #endif /* !FORCEINLINE */
230
231 /*
232  * Other functions visible externally
233  */
234
235 /** Find common character attributes for the start of a string.
236  * @param[in] s Input string to scan.
237  * @param[in] n Maximum number of bytes to check.
238  * @return Bitmask of all character attributes shared by the start of \a s.
239  */
240 int strnChattr(const char *s, const size_t n)
241 {
242   const char *rs = s;
243   unsigned int x = ~0;
244   int r = n;
245   while (*rs && r--)
246     x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN];
247   return x;
248 }
249
250 /** Case insensitive string comparison.
251  * @param[in] a First string to compare.
252  * @param[in] b Second string to compare.
253  * @return Less than, equal to, or greater than zero if \a a is lexicographically less than, equal to, or greater than \a b.
254  */
255 int ircd_strcmp(const char *a, const char *b)
256 {
257   const char* ra = a;
258   const char* rb = b;
259   while (ToLower(*ra) == ToLower(*rb)) {
260     if (!*ra++)
261       return 0;
262     else
263       ++rb;
264   }
265   return (ToLower(*ra) - ToLower(*rb));
266 }
267
268 /** Case insensitive comparison of the starts of two strings.
269  * @param[in] a First string to compare.
270  * @param[in] b Second string to compare.
271  * @param[in] n Maximum number of characters to compare.
272  * @return Less than, equal to, or greater than zero if \a a is
273  * lexicographically less than, equal to, or greater than \a b.
274  */
275 int ircd_strncmp(const char *a, const char *b, size_t n)
276 {
277   const char* ra = a;
278   const char* rb = b;
279   int left = n;
280   if (!left--)
281     return 0;
282   while (ToLower(*ra) == ToLower(*rb)) {
283     if (!*ra++ || !left--)
284       return 0;
285     else
286       ++rb;
287   }
288   return (ToLower(*ra) - ToLower(*rb));
289 }
290
291 /** Fill a vector of distinct names from a delimited input list.
292  * Empty tokens (when \a token occurs at the start or end of \a list,
293  * or when \a token occurs adjacent to itself) are ignored.  When
294  * \a size tokens have been written to \a vector, the rest of the
295  * string is ignored.
296  * Unlike token_vector(), if a token repeats an earlier token, it is
297  * skipped.
298  * @param[in,out] names Input buffer.
299  * @param[in] token Delimiter used to split \a list.
300  * @param[out] vector Output vector.
301  * @param[in] size Maximum number of elements to put in \a vector.
302  * @return Number of elements written to \a vector.
303  */
304 int unique_name_vector(char* names, char token, char** vector, int size)
305 {
306   int   i;
307   int   count = 0;
308   char* start = names;
309   char* end;
310
311   assert(0 != names);
312   assert(0 != vector);
313   assert(0 < size);
314
315   /*
316    * ignore spurious tokens
317    */
318   while (token == *start)
319     ++start;
320
321   for (end = strchr(start, token); end; end = strchr(start, token)) {
322     *end++ = '\0';
323     /*
324      * ignore spurious tokens
325      */
326     while (token == *end)
327       ++end;
328     for (i = 0; i < count; ++i) {
329       if (0 == ircd_strcmp(vector[i], start))
330         break;
331     }
332     if (i == count) {
333       vector[count++] = start;
334       if (count == size)
335         return count;
336     }
337     start = end;
338   }
339   if (*start) {
340     for (i = 0; i < count; ++i)
341       if (0 == ircd_strcmp(vector[i], start))
342         return count;
343     vector[count++] = start;
344   }
345   return count;
346 }
347
348 /** Fill a vector of tokens from a delimited input list.
349  * Empty tokens (when \a token occurs at the start or end of \a list,
350  * or when \a token occurs adjacent to itself) are ignored.  When
351  * \a size tokens have been written to \a vector, the rest of the
352  * string is ignored.
353  * @param[in,out] names Input buffer.
354  * @param[in] token Delimiter used to split \a list.
355  * @param[out] vector Output vector.
356  * @param[in] size Maximum number of elements to put in \a vector.
357  * @return Number of elements written to \a vector.
358  */
359 int token_vector(char* names, char token, char** vector, int size)
360 {
361   int   count = 0;
362   char* start = names;
363   char* end;
364
365   assert(0 != names);
366   assert(0 != vector);
367   assert(1 < size);
368
369   vector[count++] = start;
370   for (end = strchr(start, token); end; end = strchr(start, token)) {
371     *end++ = '\0';
372     start = end;
373     if (*start) {
374       vector[count++] = start;
375       if (count < size)
376         continue;
377     }
378     break;
379   }
380   return count;
381 }
382
383 /** Copy all or part of the hostname in a string to another string.
384  * If \a userhost contains an '\@', the remaining portion is used;
385  * otherwise, the whole \a userhost is used.
386  * @param[out] buf Output buffer.
387  * @param[in] userhost user\@hostname or hostname string.
388  * @param[in] len Maximum number of bytes to write to \a host.
389  * @return The output buffer \a buf.
390  */
391 char* host_from_uh(char* buf, const char* userhost, size_t len)
392 {
393   const char* s;
394
395   assert(0 != buf);
396   assert(0 != userhost);
397
398   if ((s = strchr(userhost, '@')))
399     ++s;
400   else
401     s = userhost;
402   ircd_strncpy(buf, s, len);
403   buf[len] = '\0';
404   return buf;
405 }
406
407 /*
408  * this new faster inet_ntoa was ripped from:
409  * From: Thomas Helvey <tomh@inxpress.net>
410  */
411 /** Array of text strings for dotted quads. */
412 static const char* IpQuadTab[] =
413 {
414     "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
415    "10",  "11",  "12",  "13",  "14",  "15",  "16",  "17",  "18",  "19",
416    "20",  "21",  "22",  "23",  "24",  "25",  "26",  "27",  "28",  "29",
417    "30",  "31",  "32",  "33",  "34",  "35",  "36",  "37",  "38",  "39",
418    "40",  "41",  "42",  "43",  "44",  "45",  "46",  "47",  "48",  "49",
419    "50",  "51",  "52",  "53",  "54",  "55",  "56",  "57",  "58",  "59",
420    "60",  "61",  "62",  "63",  "64",  "65",  "66",  "67",  "68",  "69",
421    "70",  "71",  "72",  "73",  "74",  "75",  "76",  "77",  "78",  "79",
422    "80",  "81",  "82",  "83",  "84",  "85",  "86",  "87",  "88",  "89",
423    "90",  "91",  "92",  "93",  "94",  "95",  "96",  "97",  "98",  "99",
424   "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
425   "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
426   "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
427   "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
428   "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
429   "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
430   "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
431   "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
432   "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
433   "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
434   "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
435   "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
436   "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
437   "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
438   "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
439   "250", "251", "252", "253", "254", "255"
440 };
441
442 /** Convert an IP address to printable ASCII form.
443  * This is generally deprecated in favor of ircd_ntoa_r().
444  * @param[in] in Address to convert.
445  * @return Pointer to a static buffer containing the readable form.
446  */
447 const char* ircd_ntoa(const struct irc_in_addr* in)
448 {
449   static char buf[SOCKIPLEN];
450   return ircd_ntoa_r(buf, in);
451 }
452
453 /** Convert an IP address to printable ASCII form.
454  * @param[out] buf Output buffer to write to.
455  * @param[in] in Address to format.
456  * @return Pointer to the output buffer \a buf.
457  */
458 const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in)
459 {
460     assert(buf != NULL);
461     assert(in != NULL);
462
463     if (irc_in_addr_is_ipv4(in)) {
464       unsigned int pos, len;
465       unsigned char *pch;
466
467       pch = (unsigned char*)&in->in6_16[6];
468       len = strlen(IpQuadTab[*pch]);
469       memcpy(buf, IpQuadTab[*pch++], len);
470       pos = len;
471       buf[pos++] = '.';
472       len = strlen(IpQuadTab[*pch]);
473       memcpy(buf+pos, IpQuadTab[*pch++], len);
474       pos += len;
475       buf[pos++] = '.';
476       len = strlen(IpQuadTab[*pch]);
477       memcpy(buf+pos, IpQuadTab[*pch++], len);
478       pos += len;
479       buf[pos++] = '.';
480       len = strlen(IpQuadTab[*pch]);
481       memcpy(buf+pos, IpQuadTab[*pch++], len);
482       buf[pos + len] = '\0';
483       return buf;
484     } else {
485       static const char hexdigits[] = "0123456789abcdef";
486       unsigned int pos, part, max_start, max_zeros, curr_zeros, ii;
487
488       /* Find longest run of zeros. */
489       for (max_start = ii = 1, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
490         if (!in->in6_16[ii])
491           curr_zeros++;
492         else if (curr_zeros > max_zeros) {
493           max_start = ii - curr_zeros;
494           max_zeros = curr_zeros;
495           curr_zeros = 0;
496         }
497       }
498       if (curr_zeros > max_zeros) {
499         max_start = ii - curr_zeros;
500         max_zeros = curr_zeros;
501       }
502
503       /* Print out address. */
504 /** Append \a CH to the output buffer. */
505 #define APPEND(CH) do { buf[pos++] = (CH); } while (0)
506       for (pos = ii = 0; (ii < 8); ++ii) {
507         if ((max_zeros > 0) && (ii == max_start)) {
508           APPEND(':');
509           ii += max_zeros - 1;
510           continue;
511         }
512         part = ntohs(in->in6_16[ii]);
513         if (part >= 0x1000)
514           APPEND(hexdigits[part >> 12]);
515         if (part >= 0x100)
516           APPEND(hexdigits[(part >> 8) & 15]);
517         if (part >= 0x10)
518           APPEND(hexdigits[(part >> 4) & 15]);
519         APPEND(hexdigits[part & 15]);
520         if (ii < 7)
521           APPEND(':');
522       }
523 #undef APPEND
524
525       /* Nul terminate and return number of characters used. */
526       buf[pos++] = '\0';
527       return buf;
528     }
529 }
530
531 /** Attempt to parse an IPv4 address into a network-endian form.
532  * @param[in] input Input string.
533  * @param[out] output Network-endian representation of the address.
534  * @return Number of characters used from \a input, or 0 if the parse failed.
535  */
536 static unsigned int
537 ircd_aton_ip4(const char *input, unsigned int *output)
538 {
539   unsigned int dots = 0, pos = 0, part = 0, ip = 0;
540
541   /* Intentionally no support for bizarre IPv4 formats (plain
542    * integers, octal or hex components) -- only vanilla dotted
543    * decimal quads.
544    */
545   if (input[0] == '.')
546     return 0;
547   while (1) {
548     if (IsDigit(input[pos])) {
549       part = part * 10 + input[pos++] - '0';
550       if (part > 255)
551         return 0;
552       if ((dots == 3) && !IsDigit(input[pos])) {
553         *output = htonl(ip | part);
554         return pos;
555       }
556     } else if (input[pos] == '.') {
557       if (input[++pos] == '.')
558         return 0;
559       ip |= part << (24 - 8 * dots++);
560       part = 0;
561     } else
562       return 0;
563   }
564 }
565
566 /** Parse a numeric IPv4 or IPv6 address into an irc_in_addr.
567  * @param[out] ip Receives parsed IP address.
568  * @param[in] input Input buffer.
569  * @return Number of characters used from \a input, or 0 if the
570  * address was unparseable or malformed.
571  */
572 int
573 ircd_aton(struct irc_in_addr *ip, const char *input)
574 {
575   char *colon;
576   char *dot;
577
578   assert(ip);
579   assert(input);
580   memset(ip, 0, sizeof(*ip));
581   colon = strchr(input, ':');
582   dot = strchr(input, '.');
583
584   if (colon && (!dot || (dot > colon))) {
585     unsigned int part = 0, pos = 0, ii = 0, colon = 8;
586     const char *part_start = NULL;
587
588     /* Parse IPv6, possibly like ::127.0.0.1.
589      * This is pretty straightforward; the only trick is borrowed
590      * from Paul Vixie (BIND): when it sees a "::" continue as if
591      * it were a single ":", but note where it happened, and fill
592      * with zeros afterward.
593      */
594     if (input[pos] == ':') {
595       if ((input[pos+1] != ':') || (input[pos+2] == ':'))
596         return 0;
597       colon = 0;
598       pos += 2;
599       part_start = input + pos;
600     }
601     while (ii < 8) {
602       unsigned char chval;
603
604       switch (input[pos]) {
605       case '0': case '1': case '2': case '3': case '4':
606       case '5': case '6': case '7': case '8': case '9':
607           chval = input[pos] - '0';
608       use_chval:
609         part = (part << 4) | chval;
610         if (part > 0xffff)
611           return 0;
612         pos++;
613         break;
614       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
615           chval = input[pos] - 'A' + 10;
616           goto use_chval;
617       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
618           chval = input[pos] - 'a' + 10;
619           goto use_chval;
620       case ':':
621         part_start = input + ++pos;
622         if (input[pos] == '.')
623           return 0;
624         ip->in6_16[ii++] = htons(part);
625         part = 0;
626         if (input[pos] == ':') {
627           if (colon < 8)
628             return 0;
629           colon = ii;
630           pos++;
631         }
632         break;
633       case '.': {
634         uint32_t ip4;
635         unsigned int len;
636         len = ircd_aton_ip4(part_start, &ip4);
637         if (!len || (ii > 6))
638           return 0;
639         ip->in6_16[ii++] = htons(ntohl(ip4) >> 16);
640         ip->in6_16[ii++] = htons(ntohl(ip4) & 65535);
641         if (colon < 8) {
642           unsigned int jj;
643           /* Shift stuff after "::" up and fill middle with zeros. */
644           for (jj = 0; jj < ii - colon; jj++)
645             ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
646           for (jj = 0; jj < 8 - ii; jj++)
647             ip->in6_16[colon + jj] = 0;
648         }
649         return part_start - input + len;
650       }
651       default: {
652         ip->in6_16[ii++] = htons(part);
653         if (colon < 8) {
654           unsigned int jj;
655           /* Shift stuff after "::" up and fill middle with zeros. */
656           for (jj = 0; jj < ii - colon; jj++)
657             ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
658           for (jj = 0; jj < 8 - ii; jj++)
659             ip->in6_16[colon + jj] = 0;
660         }
661         return pos;
662       }
663       }
664     }
665     return pos;
666   } else if (dot) {
667     unsigned int addr;
668     int len = ircd_aton_ip4(input, &addr);
669     if (len) {
670       ip->in6_16[5] = htons(65535);
671       ip->in6_16[6] = htons(ntohl(addr) >> 16);
672       ip->in6_16[7] = htons(ntohl(addr) & 65535);
673       return len;
674     }
675   }
676   return 0; /* parse failed */
677 }