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];
386 char *silc_id_render(void *id, SilcUInt16 type)
389 unsigned char tmps[2];
391 memset(rid, 0, sizeof(rid));
395 SilcServerID *server_id = (SilcServerID *)id;
396 if (server_id->ip.data_len > 4) {
398 struct in6_addr ipv6;
399 memmove(&ipv6, server_id->ip.data, sizeof(ipv6));
400 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
405 memmove(&ipv4.s_addr, server_id->ip.data, 4);
406 strcat(rid, inet_ntoa(ipv4));
409 memset(tmp, 0, sizeof(tmp));
410 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
412 SILC_PUT16_MSB(server_id->rnd, tmps);
413 memset(tmp, 0, sizeof(tmp));
414 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
420 SilcClientID *client_id = (SilcClientID *)id;
421 if (client_id->ip.data_len > 4) {
423 struct in6_addr ipv6;
424 memmove(&ipv6, client_id->ip.data, sizeof(ipv6));
425 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
430 memmove(&ipv4.s_addr, client_id->ip.data, 4);
431 strcat(rid, inet_ntoa(ipv4));
434 memset(tmp, 0, sizeof(tmp));
435 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
437 memset(tmp, 0, sizeof(tmp));
438 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
439 client_id->hash[0], client_id->hash[1],
440 client_id->hash[2], client_id->hash[3]);
444 case SILC_ID_CHANNEL:
446 SilcChannelID *channel_id = (SilcChannelID *)id;
447 if (channel_id->ip.data_len > 4) {
449 struct in6_addr ipv6;
450 memmove(&ipv6, channel_id->ip.data, sizeof(ipv6));
451 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
456 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
457 strcat(rid, inet_ntoa(ipv4));
460 memset(tmp, 0, sizeof(tmp));
461 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
463 SILC_PUT16_MSB(channel_id->rnd, tmps);
464 memset(tmp, 0, sizeof(tmp));
465 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
474 /* Compares two strings. Strings may include wildcards * and ?.
475 Returns TRUE if strings match. */
477 int silc_string_compare(char *string1, char *string2)
482 char *tmpstr1, *tmpstr2;
484 if (!string1 || !string2)
487 slen1 = strlen(string1);
488 slen2 = strlen(string2);
490 /* See if they are same already */
491 if (!strncmp(string1, string2, strlen(string2)))
495 if (!strchr(string1, '*'))
498 /* Take copies of the original strings as we will change them */
499 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
500 memcpy(tmpstr1, string1, slen1);
501 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
502 memcpy(tmpstr2, string2, slen2);
504 for (i = 0; i < slen1; i++) {
506 /* * wildcard. Only one * wildcard is possible. */
507 if (tmpstr1[i] == '*')
508 if (!strncmp(tmpstr1, tmpstr2, i)) {
509 memset(tmpstr2, 0, slen2);
510 strncpy(tmpstr2, tmpstr1, i);
515 if (tmpstr1[i] == '?') {
516 if (!strncmp(tmpstr1, tmpstr2, i)) {
517 if (!(slen1 < i + 1))
518 if (tmpstr1[i + 1] != '?' &&
519 tmpstr1[i + 1] != tmpstr2[i + 1])
522 if (!(slen1 < slen2))
528 /* if using *, remove it */
529 if (strchr(tmpstr1, '*'))
530 *strchr(tmpstr1, '*') = 0;
532 if (!strcmp(tmpstr1, tmpstr2)) {
533 memset(tmpstr1, 0, slen1);
534 memset(tmpstr2, 0, slen2);
540 memset(tmpstr1, 0, slen1);
541 memset(tmpstr2, 0, slen2);
547 /* Basic has function to hash strings. May be used with the SilcHashTable.
548 Note that this lowers the characters of the string (with tolower()) so
549 this is used usually with nicknames, channel and server names to provide
550 case insensitive keys. */
552 SilcUInt32 silc_hash_string(void *key, void *user_context)
554 char *s = (char *)key;
558 h = (h << 4) + tolower(*s);
559 if ((g = h & 0xf0000000)) {
569 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
571 SilcUInt32 silc_hash_uint(void *key, void *user_context)
573 return *(SilcUInt32 *)key;
576 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
578 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
580 return (SilcUInt32)key;
583 /* Hash a ID. The `user_context' is the ID type. */
585 SilcUInt32 silc_hash_id(void *key, void *user_context)
587 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
594 SilcClientID *id = (SilcClientID *)key;
597 /* The client ID is hashed by hashing the hash of the ID
598 (which is a truncated MD5 hash of the nickname) so that we
599 can access the entry from the cache with both Client ID but
600 with just a hash from the ID as well. */
602 for (i = 0; i < sizeof(id->hash); i++) {
603 h = (h << 4) + id->hash[i];
604 if ((g = h & 0xf0000000)) {
615 SilcServerID *id = (SilcServerID *)key;
617 h = id->port * id->rnd;
618 for (i = 0; i < id->ip.data_len; i++)
624 case SILC_ID_CHANNEL:
626 SilcChannelID *id = (SilcChannelID *)key;
628 h = id->port * id->rnd;
629 for (i = 0; i < id->ip.data_len; i++)
642 /* Hash binary data. The `user_context' is the data length. */
644 SilcUInt32 silc_hash_data(void *key, void *user_context)
646 SilcUInt32 len = (SilcUInt32)user_context, h = 0;
647 unsigned char *data = (unsigned char *)key;
650 h = (data[0] * data[len - 1] + 1) * len;
651 for (i = 0; i < len; i++)
657 /* Hashed SILC Public key. */
659 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
661 SilcPublicKey pk = (SilcPublicKey)key;
662 return (pk->len + silc_hash_string(pk->name, NULL) +
663 silc_hash_string(pk->identifier, NULL) +
664 silc_hash_data(pk->pk, (void *)pk->pk_len));
667 /* Compares two strings. May be used as SilcHashTable comparison function. */
669 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
671 return !strcasecmp((char *)key1, (char *)key2);
674 /* Compares two ID's. May be used as SilcHashTable comparison function.
675 The Client ID's compares only the hash of the Client ID not any other
676 part of the Client ID. Other ID's are fully compared. */
678 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
680 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
681 return (id_type == SILC_ID_CLIENT ?
682 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
683 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
686 /* Compare two Client ID's entirely and not just the hash from the ID. */
688 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
690 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
693 /* Compares binary data. May be used as SilcHashTable comparison function. */
695 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
697 SilcUInt32 len = (SilcUInt32)user_context;
698 return !memcmp(key1, key2, len);
701 /* Compares two SILC Public keys. May be used as SilcHashTable comparison
704 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
706 return silc_pkcs_public_key_compare(key1, key2);
709 /* Parses mode mask and returns the mode as string. */
711 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
718 memset(string, 0, sizeof(string));
720 if (mode & SILC_CHANNEL_MODE_PRIVATE)
721 strncat(string, "p", 1);
723 if (mode & SILC_CHANNEL_MODE_SECRET)
724 strncat(string, "s", 1);
726 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
727 strncat(string, "k", 1);
729 if (mode & SILC_CHANNEL_MODE_INVITE)
730 strncat(string, "i", 1);
732 if (mode & SILC_CHANNEL_MODE_TOPIC)
733 strncat(string, "t", 1);
735 if (mode & SILC_CHANNEL_MODE_ULIMIT)
736 strncat(string, "l", 1);
738 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
739 strncat(string, "a", 1);
741 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
742 strncat(string, "f", 1);
744 if (mode & SILC_CHANNEL_MODE_CIPHER)
745 strncat(string, cipher, strlen(cipher));
747 if (mode & SILC_CHANNEL_MODE_HMAC)
748 strncat(string, hmac, strlen(hmac));
750 /* Rest of mode is ignored */
752 return strdup(string);
755 /* Parses channel user mode mask and returns te mode as string */
757 char *silc_client_chumode(SilcUInt32 mode)
764 memset(string, 0, sizeof(string));
766 if (mode & SILC_CHANNEL_UMODE_CHANFO)
767 strncat(string, "f", 1);
769 if (mode & SILC_CHANNEL_UMODE_CHANOP)
770 strncat(string, "o", 1);
772 return strdup(string);
775 /* Parses channel user mode and returns it as special mode character. */
777 char *silc_client_chumode_char(SilcUInt32 mode)
784 memset(string, 0, sizeof(string));
786 if (mode & SILC_CHANNEL_UMODE_CHANFO)
787 strncat(string, "*", 1);
789 if (mode & SILC_CHANNEL_UMODE_CHANOP)
790 strncat(string, "@", 1);
792 return strdup(string);
795 /* Creates fingerprint from data, usually used with SHA1 digests */
797 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
799 char fingerprint[64], *cp;
802 memset(fingerprint, 0, sizeof(fingerprint));
804 for (i = 0; i < data_len; i++) {
805 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
808 if ((i + 1) % 2 == 0)
809 snprintf(cp++, sizeof(fingerprint), " ");
811 if ((i + 1) % 10 == 0)
812 snprintf(cp++, sizeof(fingerprint), " ");
815 if ((i + 1) % 2 == 0)
817 if ((i + 1) % 10 == 0)
820 return strdup(fingerprint);