5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 * These are general utility functions that doesn't belong to any specific
25 #include "silcincludes.h"
27 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
28 This doesn't remove the newline sign from the destination buffer. The
29 argument begin is returned and should be passed again for the function. */
31 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
36 memset(dest, 0, destlen);
42 for ( ; start <= srclen; i++, start++) {
59 /* Checks line for illegal characters. Return -1 when illegal character
60 were found. This is used to check for bad lines when reading data from
61 for example a configuration file. */
63 int silc_check_line(char *buf)
65 /* Illegal characters in line */
66 if (strchr(buf, '#')) return -1;
67 if (strchr(buf, '\'')) return -1;
68 if (strchr(buf, '\\')) return -1;
69 if (strchr(buf, '\r')) return -1;
70 if (strchr(buf, '\a')) return -1;
71 if (strchr(buf, '\b')) return -1;
72 if (strchr(buf, '\f')) return -1;
81 /* Returns current time as string. */
89 return_time = ctime(&curtime);
90 return_time[strlen(return_time) - 1] = '\0';
95 /* Converts string to capital characters */
97 char *silc_to_upper(char *string)
100 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
102 for (i = 0; i < strlen(string); i++)
103 ret[i] = toupper(string[i]);
108 static unsigned char pem_enc[64] =
109 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
111 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
112 data string. Note: This is originally public domain code and is
115 char *silc_encode_pem(unsigned char *data, SilcUInt32 len)
118 SilcUInt32 bits, c, char_count;
125 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
127 for (i = 0; i < len; i++) {
132 if (char_count == 3) {
133 pem[j++] = pem_enc[bits >> 18];
134 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
135 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
136 pem[j++] = pem_enc[bits & 0x3f];
144 if (char_count != 0) {
145 bits <<= 16 - (8 * char_count);
146 pem[j++] = pem_enc[bits >> 18];
147 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
149 if (char_count == 1) {
153 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
161 /* Same as above but puts newline ('\n') every 72 characters. */
163 char *silc_encode_pem_file(unsigned char *data, SilcUInt32 data_len)
166 SilcUInt32 len, cols;
169 pem = silc_encode_pem(data, data_len);
172 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
174 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
189 /* Decodes PEM into data. Returns the decoded data. Note: This is
190 originally public domain code and is still PD. */
192 unsigned char *silc_decode_pem(unsigned char *pem, SilcUInt32 pem_len,
196 SilcUInt32 len, c, char_count, bits;
198 static char ialpha[256], decoder[256];
200 for (i = 64 - 1; i >= 0; i--) {
201 ialpha[pem_enc[i]] = 1;
202 decoder[pem_enc[i]] = i;
214 data = silc_calloc(((len * 6) / 8), sizeof(*data));
216 for (i = 0; i < len; i++) {
222 if (c > 127 || !ialpha[c])
228 if (char_count == 4) {
229 data[j++] = bits >> 16;
230 data[j++] = (bits >> 8) & 0xff;
231 data[j++] = bits & 0xff;
245 data[j++] = bits >> 10;
248 data[j++] = bits >> 16;
249 data[j++] = (bits >> 8) & 0xff;
259 /* Parse userfqdn string which is in user@fqdn format */
261 bool silc_parse_userfqdn(const char *string, char **left, char **right)
268 if (string[0] == '@') {
270 *left = strdup(string);
274 if (strchr(string, '@')) {
275 tlen = strcspn(string, "@");
278 *left = silc_calloc(tlen + 1, sizeof(char));
279 memcpy(*left, string, tlen);
283 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
284 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
288 *left = strdup(string);
294 /* Parses command line. At most `max_args' is taken. Rest of the line
295 will be allocated as the last argument if there are more than `max_args'
296 arguments in the line. Note that the command name is counted as one
297 argument and is saved. */
299 void silc_parse_command_line(unsigned char *buffer,
300 unsigned char ***parsed,
301 SilcUInt32 **parsed_lens,
302 SilcUInt32 **parsed_types,
303 SilcUInt32 *parsed_num,
308 const char *cp = buffer;
311 *parsed = silc_calloc(1, sizeof(**parsed));
312 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
314 /* Get the command first */
315 len = strcspn(cp, " ");
316 tmp = silc_to_upper((char *)cp);
317 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
318 memcpy((*parsed)[0], tmp, len);
320 (*parsed_lens)[0] = len;
326 /* Parse arguments */
327 if (strchr(cp, ' ') || strlen(cp) != 0) {
328 for (i = 1; i < max_args; i++) {
330 if (i != max_args - 1)
331 len = strcspn(cp, " ");
334 while (len && cp[len - 1] == ' ')
339 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
340 *parsed_lens = silc_realloc(*parsed_lens,
341 sizeof(**parsed_lens) * (argc + 1));
342 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
343 memcpy((*parsed)[argc], cp, len);
344 (*parsed_lens)[argc] = len;
356 /* Save argument types. Protocol defines all argument types but
357 this implementation makes sure that they are always in correct
358 order hence this simple code. */
359 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
360 for (i = 0; i < argc; i++)
361 (*parsed_types)[i] = i;
366 /* Formats arguments to a string and returns it after allocating memory
367 for it. It must be remembered to free it later. */
369 char *silc_format(char *fmt, ...)
372 static char buf[8192];
374 memset(buf, 0, sizeof(buf));
376 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
382 /* Renders ID to suitable to print for example to log file. */
384 static char rid[256];
385 #define _PUT_STRING(d, s) \
387 int sp = (sizeof(d) - 1) - strlen(d); \
388 if (sp < strlen(s)) { \
390 strncat(d, s, (sizeof(d) - 1) - strlen(d)); \
392 strncat(d, s, strlen(s)); \
396 char *silc_id_render(void *id, SilcUInt16 type)
399 unsigned char tmps[2];
402 memset(rid, 0, sizeof(rid));
406 SilcServerID *server_id = (SilcServerID *)id;
407 if (server_id->ip.data_len > 4) {
409 struct sockaddr_in6 ipv6;
410 memset(&ipv6, 0, sizeof(ipv6));
411 ipv6.sin6_family = AF_INET6;
412 memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
413 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
414 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
415 _PUT_STRING(rid, tmp);
419 memmove(&ipv4.s_addr, server_id->ip.data, 4);
420 cp = inet_ntoa(ipv4);
422 _PUT_STRING(rid, cp);
425 memset(tmp, 0, sizeof(tmp));
426 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
427 _PUT_STRING(rid, tmp);
428 SILC_PUT16_MSB(server_id->rnd, tmps);
429 memset(tmp, 0, sizeof(tmp));
430 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
431 _PUT_STRING(rid, tmp);
436 SilcClientID *client_id = (SilcClientID *)id;
437 if (client_id->ip.data_len > 4) {
439 struct sockaddr_in6 ipv6;
440 memset(&ipv6, 0, sizeof(ipv6));
441 ipv6.sin6_family = AF_INET6;
442 memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
443 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
444 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
445 _PUT_STRING(rid, tmp);
449 memmove(&ipv4.s_addr, client_id->ip.data, 4);
450 cp = inet_ntoa(ipv4);
452 _PUT_STRING(rid, cp);
455 memset(tmp, 0, sizeof(tmp));
456 snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
457 _PUT_STRING(rid, tmp);
458 memset(tmp, 0, sizeof(tmp));
459 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
460 client_id->hash[0], client_id->hash[1],
461 client_id->hash[2], client_id->hash[3]);
462 _PUT_STRING(rid, tmp);
465 case SILC_ID_CHANNEL:
467 SilcChannelID *channel_id = (SilcChannelID *)id;
468 if (channel_id->ip.data_len > 4) {
470 struct sockaddr_in6 ipv6;
471 memset(&ipv6, 0, sizeof(ipv6));
472 ipv6.sin6_family = AF_INET6;
473 memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
474 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
475 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
476 _PUT_STRING(rid, tmp);
480 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
481 cp = inet_ntoa(ipv4);
483 _PUT_STRING(rid, cp);
486 memset(tmp, 0, sizeof(tmp));
487 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
488 _PUT_STRING(rid, tmp);
489 SILC_PUT16_MSB(channel_id->rnd, tmps);
490 memset(tmp, 0, sizeof(tmp));
491 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
492 _PUT_STRING(rid, tmp);
500 /* Compares two strings. Strings may include wildcards * and ?.
501 Returns TRUE if strings match. */
503 int silc_string_compare(char *string1, char *string2)
508 char *tmpstr1, *tmpstr2;
510 if (!string1 || !string2)
513 slen1 = strlen(string1);
514 slen2 = strlen(string2);
516 /* See if they are same already */
517 if (!strncmp(string1, string2, strlen(string2)))
521 if (!strchr(string1, '*'))
524 /* Take copies of the original strings as we will change them */
525 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
526 memcpy(tmpstr1, string1, slen1);
527 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
528 memcpy(tmpstr2, string2, slen2);
530 for (i = 0; i < slen1; i++) {
532 /* * wildcard. Only one * wildcard is possible. */
533 if (tmpstr1[i] == '*')
534 if (!strncmp(tmpstr1, tmpstr2, i)) {
535 memset(tmpstr2, 0, slen2);
536 strncpy(tmpstr2, tmpstr1, i);
541 if (tmpstr1[i] == '?') {
542 if (!strncmp(tmpstr1, tmpstr2, i)) {
543 if (!(slen1 < i + 1))
544 if (tmpstr1[i + 1] != '?' &&
545 tmpstr1[i + 1] != tmpstr2[i + 1])
548 if (!(slen1 < slen2))
554 /* if using *, remove it */
555 if (strchr(tmpstr1, '*'))
556 *strchr(tmpstr1, '*') = 0;
558 if (!strcmp(tmpstr1, tmpstr2)) {
559 memset(tmpstr1, 0, slen1);
560 memset(tmpstr2, 0, slen2);
566 memset(tmpstr1, 0, slen1);
567 memset(tmpstr2, 0, slen2);
573 /* Basic has function to hash strings. May be used with the SilcHashTable.
574 Note that this lowers the characters of the string (with tolower()) so
575 this is used usually with nicknames, channel and server names to provide
576 case insensitive keys. */
578 SilcUInt32 silc_hash_string(void *key, void *user_context)
580 char *s = (char *)key;
584 h = (h << 4) + tolower(*s);
585 if ((g = h & 0xf0000000)) {
595 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
597 SilcUInt32 silc_hash_uint(void *key, void *user_context)
599 return *(SilcUInt32 *)key;
602 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
604 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
606 return (SilcUInt32)key;
609 /* Hash a ID. The `user_context' is the ID type. */
611 SilcUInt32 silc_hash_id(void *key, void *user_context)
613 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
620 SilcClientID *id = (SilcClientID *)key;
623 /* The client ID is hashed by hashing the hash of the ID
624 (which is a truncated MD5 hash of the nickname) so that we
625 can access the entry from the cache with both Client ID but
626 with just a hash from the ID as well. */
628 for (i = 0; i < sizeof(id->hash); i++) {
629 h = (h << 4) + id->hash[i];
630 if ((g = h & 0xf0000000)) {
641 SilcServerID *id = (SilcServerID *)key;
643 h = id->port * id->rnd;
644 for (i = 0; i < id->ip.data_len; i++)
650 case SILC_ID_CHANNEL:
652 SilcChannelID *id = (SilcChannelID *)key;
654 h = id->port * id->rnd;
655 for (i = 0; i < id->ip.data_len; i++)
668 /* Hash binary data. The `user_context' is the data length. */
670 SilcUInt32 silc_hash_data(void *key, void *user_context)
672 SilcUInt32 len = (SilcUInt32)user_context, h = 0;
673 unsigned char *data = (unsigned char *)key;
676 h = (data[0] * data[len - 1] + 1) * len;
677 for (i = 0; i < len; i++)
683 /* Hashed SILC Public key. */
685 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
687 SilcPublicKey pk = (SilcPublicKey)key;
688 return (pk->len + silc_hash_string(pk->name, NULL) +
689 silc_hash_string(pk->identifier, NULL) +
690 silc_hash_data(pk->pk, (void *)pk->pk_len));
693 /* Compares two strings. May be used as SilcHashTable comparison function. */
695 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
697 return !strcasecmp((char *)key1, (char *)key2);
700 /* Compares two ID's. May be used as SilcHashTable comparison function.
701 The Client ID's compares only the hash of the Client ID not any other
702 part of the Client ID. Other ID's are fully compared. */
704 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
706 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
707 return (id_type == SILC_ID_CLIENT ?
708 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
709 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
712 /* Compare two Client ID's entirely and not just the hash from the ID. */
714 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
716 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
719 /* Compares binary data. May be used as SilcHashTable comparison function. */
721 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
723 SilcUInt32 len = (SilcUInt32)user_context;
724 return !memcmp(key1, key2, len);
727 /* Compares two SILC Public keys. May be used as SilcHashTable comparison
730 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
732 return silc_pkcs_public_key_compare(key1, key2);
735 /* Parses mode mask and returns the mode as string. */
737 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
744 memset(string, 0, sizeof(string));
746 if (mode & SILC_CHANNEL_MODE_PRIVATE)
747 strncat(string, "p", 1);
749 if (mode & SILC_CHANNEL_MODE_SECRET)
750 strncat(string, "s", 1);
752 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
753 strncat(string, "k", 1);
755 if (mode & SILC_CHANNEL_MODE_INVITE)
756 strncat(string, "i", 1);
758 if (mode & SILC_CHANNEL_MODE_TOPIC)
759 strncat(string, "t", 1);
761 if (mode & SILC_CHANNEL_MODE_ULIMIT)
762 strncat(string, "l", 1);
764 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
765 strncat(string, "a", 1);
767 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
768 strncat(string, "f", 1);
770 if (mode & SILC_CHANNEL_MODE_CIPHER)
771 strncat(string, cipher, strlen(cipher));
773 if (mode & SILC_CHANNEL_MODE_HMAC)
774 strncat(string, hmac, strlen(hmac));
776 /* Rest of mode is ignored */
778 return strdup(string);
781 /* Parses channel user mode mask and returns te mode as string */
783 char *silc_client_chumode(SilcUInt32 mode)
790 memset(string, 0, sizeof(string));
792 if (mode & SILC_CHANNEL_UMODE_CHANFO)
793 strncat(string, "f", 1);
795 if (mode & SILC_CHANNEL_UMODE_CHANOP)
796 strncat(string, "o", 1);
798 return strdup(string);
801 /* Parses channel user mode and returns it as special mode character. */
803 char *silc_client_chumode_char(SilcUInt32 mode)
810 memset(string, 0, sizeof(string));
812 if (mode & SILC_CHANNEL_UMODE_CHANFO)
813 strncat(string, "*", 1);
815 if (mode & SILC_CHANNEL_UMODE_CHANOP)
816 strncat(string, "@", 1);
818 return strdup(string);
821 /* Creates fingerprint from data, usually used with SHA1 digests */
823 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
825 char fingerprint[64], *cp;
828 memset(fingerprint, 0, sizeof(fingerprint));
830 for (i = 0; i < data_len; i++) {
831 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
834 if ((i + 1) % 2 == 0)
835 snprintf(cp++, sizeof(fingerprint), " ");
837 if ((i + 1) % 10 == 0)
838 snprintf(cp++, sizeof(fingerprint), " ");
841 if ((i + 1) % 2 == 0)
843 if ((i + 1) % 10 == 0)
846 return strdup(fingerprint);
849 /* Return TRUE if the `data' is ASCII string. */
851 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
855 for (i = 0; i < data_len; i++) {
856 if (!isascii(data[i]))