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 /* Opens a file indicated by the filename `filename' with flags indicated
30 int silc_file_open(const char *filename, int flags)
34 fd = open(filename, flags, 0600);
39 /* Reads data from file descriptor `fd' to `buf'. */
41 int silc_file_read(int fd, unsigned char *buf, uint32 buf_len)
43 return read(fd, (void *)buf, buf_len);
46 /* Writes `buffer' of length of `len' to file descriptor `fd. */
48 int silc_file_write(int fd, const char *buffer, uint32 len)
50 return write(fd, (const void *)buffer, len);
53 /* Closes file descriptor */
55 int silc_file_close(int fd)
60 /* Writes a buffer to the file. */
62 int silc_file_writefile(const char *filename, const char *buffer, uint32 len)
66 if ((fd = creat(filename, 0644)) == -1) {
67 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
72 if ((write(fd, buffer, len)) == -1) {
73 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
83 /* Writes a buffer to the file. If the file is created specific mode is
86 int silc_file_writefile_mode(const char *filename, const char *buffer,
91 if ((fd = creat(filename, mode)) == -1) {
92 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
97 if ((write(fd, buffer, len)) == -1) {
98 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
108 /* Reads a file to a buffer. The allocated buffer is returned. Length of
109 the file read is returned to the return_len argument. */
111 char *silc_file_readfile(const char *filename, uint32 *return_len)
117 fd = silc_file_open(filename, O_RDONLY);
121 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
125 filelen = lseek(fd, (off_t)0L, SEEK_END);
130 if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
136 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
141 buffer = silc_calloc(filelen + 1, sizeof(char));
143 if ((read(fd, buffer, filelen)) == -1) {
144 memset(buffer, 0, sizeof(buffer));
146 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
152 buffer[filelen] = EOF;
155 *return_len = filelen;
160 /* Returns files size. Returns 0 on error. */
162 uint64 silc_file_size(const char *filename)
168 ret = lstat(filename, &stats);
170 ret = stat(filename, &stats);
175 return (uint64)stats.st_size;
178 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
179 This doesn't remove the newline sign from the destination buffer. The
180 argument begin is returned and should be passed again for the function. */
182 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
184 static int start = 0;
187 memset(dest, 0, destlen);
193 for ( ; start <= srclen; i++, start++) {
197 dest[i] = src[start];
210 /* Checks line for illegal characters. Return -1 when illegal character
211 were found. This is used to check for bad lines when reading data from
212 for example a configuration file. */
214 int silc_check_line(char *buf)
216 /* Illegal characters in line */
217 if (strchr(buf, '#')) return -1;
218 if (strchr(buf, '\'')) return -1;
219 if (strchr(buf, '\\')) return -1;
220 if (strchr(buf, '\r')) return -1;
221 if (strchr(buf, '\a')) return -1;
222 if (strchr(buf, '\b')) return -1;
223 if (strchr(buf, '\f')) return -1;
232 /* Returns current time as string. */
234 char *silc_get_time()
239 curtime = time(NULL);
240 return_time = ctime(&curtime);
241 return_time[strlen(return_time) - 1] = '\0';
246 /* Converts string to capital characters */
248 char *silc_to_upper(char *string)
251 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
253 for (i = 0; i < strlen(string); i++)
254 ret[i] = toupper(string[i]);
259 static unsigned char pem_enc[64] =
260 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
262 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
263 data string. Note: This is originally public domain code and is
266 char *silc_encode_pem(unsigned char *data, uint32 len)
269 uint32 bits, c, char_count;
276 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
278 for (i = 0; i < len; i++) {
283 if (char_count == 3) {
284 pem[j++] = pem_enc[bits >> 18];
285 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
286 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
287 pem[j++] = pem_enc[bits & 0x3f];
295 if (char_count != 0) {
296 bits <<= 16 - (8 * char_count);
297 pem[j++] = pem_enc[bits >> 18];
298 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
300 if (char_count == 1) {
304 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
312 /* Same as above but puts newline ('\n') every 72 characters. */
314 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
320 pem = silc_encode_pem(data, data_len);
323 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
325 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
340 /* Decodes PEM into data. Returns the decoded data. Note: This is
341 originally public domain code and is still PD. */
343 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
347 uint32 len, c, char_count, bits;
349 static char ialpha[256], decoder[256];
351 for (i = 64 - 1; i >= 0; i--) {
352 ialpha[pem_enc[i]] = 1;
353 decoder[pem_enc[i]] = i;
365 data = silc_calloc(((len * 6) / 8), sizeof(*data));
367 for (i = 0; i < len; i++) {
373 if (c > 127 || !ialpha[c])
379 if (char_count == 4) {
380 data[j++] = bits >> 16;
381 data[j++] = (bits >> 8) & 0xff;
382 data[j++] = bits & 0xff;
396 data[j++] = bits >> 10;
399 data[j++] = bits >> 16;
400 data[j++] = (bits >> 8) & 0xff;
410 /* Parse userfqdn string which is in user@fqdn format */
412 bool silc_parse_userfqdn(const char *string, char **left, char **right)
419 if (string[0] == '@') {
421 *left = strdup(string);
425 if (strchr(string, '@')) {
426 tlen = strcspn(string, "@");
429 *left = silc_calloc(tlen + 1, sizeof(char));
430 memcpy(*left, string, tlen);
434 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
435 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
439 *left = strdup(string);
445 /* Parses command line. At most `max_args' is taken. Rest of the line
446 will be allocated as the last argument if there are more than `max_args'
447 arguments in the line. Note that the command name is counted as one
448 argument and is saved. */
450 void silc_parse_command_line(unsigned char *buffer,
451 unsigned char ***parsed,
452 uint32 **parsed_lens,
453 uint32 **parsed_types,
459 const char *cp = buffer;
462 *parsed = silc_calloc(1, sizeof(**parsed));
463 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
465 /* Get the command first */
466 len = strcspn(cp, " ");
467 tmp = silc_to_upper((char *)cp);
468 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
469 memcpy((*parsed)[0], tmp, len);
471 (*parsed_lens)[0] = len;
477 /* Parse arguments */
478 if (strchr(cp, ' ') || strlen(cp) != 0) {
479 for (i = 1; i < max_args; i++) {
481 if (i != max_args - 1)
482 len = strcspn(cp, " ");
485 while (len && cp[len - 1] == ' ')
490 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
491 *parsed_lens = silc_realloc(*parsed_lens,
492 sizeof(**parsed_lens) * (argc + 1));
493 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
494 memcpy((*parsed)[argc], cp, len);
495 (*parsed_lens)[argc] = len;
507 /* Save argument types. Protocol defines all argument types but
508 this implementation makes sure that they are always in correct
509 order hence this simple code. */
510 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
511 for (i = 0; i < argc; i++)
512 (*parsed_types)[i] = i;
517 /* Formats arguments to a string and returns it after allocating memory
518 for it. It must be remembered to free it later. */
520 char *silc_format(char *fmt, ...)
523 static char buf[8192];
525 memset(buf, 0, sizeof(buf));
527 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
533 /* Renders ID to suitable to print for example to log file. */
535 static char rid[256];
537 char *silc_id_render(void *id, uint16 type)
540 unsigned char tmps[2];
542 memset(rid, 0, sizeof(rid));
546 SilcServerID *server_id = (SilcServerID *)id;
547 if (server_id->ip.data_len > 4) {
549 struct in6_addr ipv6;
550 memmove(&ipv6, server_id->ip.data, sizeof(ipv6));
551 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
556 memmove(&ipv4.s_addr, server_id->ip.data, 4);
557 strcat(rid, inet_ntoa(ipv4));
560 memset(tmp, 0, sizeof(tmp));
561 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
563 SILC_PUT16_MSB(server_id->rnd, tmps);
564 memset(tmp, 0, sizeof(tmp));
565 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
571 SilcClientID *client_id = (SilcClientID *)id;
572 if (client_id->ip.data_len > 4) {
574 struct in6_addr ipv6;
575 memmove(&ipv6, client_id->ip.data, sizeof(ipv6));
576 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
581 memmove(&ipv4.s_addr, client_id->ip.data, 4);
582 strcat(rid, inet_ntoa(ipv4));
585 memset(tmp, 0, sizeof(tmp));
586 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
588 memset(tmp, 0, sizeof(tmp));
589 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
590 client_id->hash[0], client_id->hash[1],
591 client_id->hash[2], client_id->hash[3]);
595 case SILC_ID_CHANNEL:
597 SilcChannelID *channel_id = (SilcChannelID *)id;
598 if (channel_id->ip.data_len > 4) {
600 struct in6_addr ipv6;
601 memmove(&ipv6, channel_id->ip.data, sizeof(ipv6));
602 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
607 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
608 strcat(rid, inet_ntoa(ipv4));
611 memset(tmp, 0, sizeof(tmp));
612 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
614 SILC_PUT16_MSB(channel_id->rnd, tmps);
615 memset(tmp, 0, sizeof(tmp));
616 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
625 /* Compares two strings. Strings may include wildcards * and ?.
626 Returns TRUE if strings match. */
628 int silc_string_compare(char *string1, char *string2)
633 char *tmpstr1, *tmpstr2;
635 if (!string1 || !string2)
638 slen1 = strlen(string1);
639 slen2 = strlen(string2);
641 /* See if they are same already */
642 if (!strncmp(string1, string2, strlen(string2)))
646 if (!strchr(string1, '*'))
649 /* Take copies of the original strings as we will change them */
650 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
651 memcpy(tmpstr1, string1, slen1);
652 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
653 memcpy(tmpstr2, string2, slen2);
655 for (i = 0; i < slen1; i++) {
657 /* * wildcard. Only one * wildcard is possible. */
658 if (tmpstr1[i] == '*')
659 if (!strncmp(tmpstr1, tmpstr2, i)) {
660 memset(tmpstr2, 0, slen2);
661 strncpy(tmpstr2, tmpstr1, i);
666 if (tmpstr1[i] == '?') {
667 if (!strncmp(tmpstr1, tmpstr2, i)) {
668 if (!(slen1 < i + 1))
669 if (tmpstr1[i + 1] != '?' &&
670 tmpstr1[i + 1] != tmpstr2[i + 1])
673 if (!(slen1 < slen2))
679 /* if using *, remove it */
680 if (strchr(tmpstr1, '*'))
681 *strchr(tmpstr1, '*') = 0;
683 if (!strcmp(tmpstr1, tmpstr2)) {
684 memset(tmpstr1, 0, slen1);
685 memset(tmpstr2, 0, slen2);
691 memset(tmpstr1, 0, slen1);
692 memset(tmpstr2, 0, slen2);
698 /* Basic has function to hash strings. May be used with the SilcHashTable.
699 Note that this lowers the characters of the string (with tolower()) so
700 this is used usually with nicknames, channel and server names to provide
701 case insensitive keys. */
703 uint32 silc_hash_string(void *key, void *user_context)
705 char *s = (char *)key;
709 h = (h << 4) + tolower(*s);
710 if ((g = h & 0xf0000000)) {
720 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
722 uint32 silc_hash_uint(void *key, void *user_context)
724 return *(uint32 *)key;
727 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
729 uint32 silc_hash_ptr(void *key, void *user_context)
734 /* Hash a ID. The `user_context' is the ID type. */
736 uint32 silc_hash_id(void *key, void *user_context)
738 SilcIdType id_type = (SilcIdType)(uint32)user_context;
745 SilcClientID *id = (SilcClientID *)key;
748 /* The client ID is hashed by hashing the hash of the ID
749 (which is a truncated MD5 hash of the nickname) so that we
750 can access the entry from the cache with both Client ID but
751 with just a hash from the ID as well. */
753 for (i = 0; i < sizeof(id->hash); i++) {
754 h = (h << 4) + id->hash[i];
755 if ((g = h & 0xf0000000)) {
766 SilcServerID *id = (SilcServerID *)key;
768 h = id->port * id->rnd;
769 for (i = 0; i < id->ip.data_len; i++)
775 case SILC_ID_CHANNEL:
777 SilcChannelID *id = (SilcChannelID *)key;
779 h = id->port * id->rnd;
780 for (i = 0; i < id->ip.data_len; i++)
793 /* Hash binary data. The `user_context' is the data length. */
795 uint32 silc_hash_data(void *key, void *user_context)
797 uint32 len = (uint32)user_context, h = 0;
798 unsigned char *data = (unsigned char *)key;
801 h = (data[0] * data[len - 1] + 1) * len;
802 for (i = 0; i < len; i++)
808 /* Compares two strings. May be used as SilcHashTable comparison function. */
810 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
812 return !strcasecmp((char *)key1, (char *)key2);
815 /* Compares two ID's. May be used as SilcHashTable comparison function.
816 The Client ID's compares only the hash of the Client ID not any other
817 part of the Client ID. Other ID's are fully compared. */
819 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
821 SilcIdType id_type = (SilcIdType)(uint32)user_context;
822 return (id_type == SILC_ID_CLIENT ?
823 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
824 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
827 /* Compare two Client ID's entirely and not just the hash from the ID. */
829 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
831 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
834 /* Compares binary data. May be used as SilcHashTable comparison function. */
836 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
838 uint32 len = (uint32)user_context;
839 return !memcmp(key1, key2, len);
842 /* Parses mode mask and returns the mode as string. */
844 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
851 memset(string, 0, sizeof(string));
853 if (mode & SILC_CHANNEL_MODE_PRIVATE)
854 strncat(string, "p", 1);
856 if (mode & SILC_CHANNEL_MODE_SECRET)
857 strncat(string, "s", 1);
859 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
860 strncat(string, "k", 1);
862 if (mode & SILC_CHANNEL_MODE_INVITE)
863 strncat(string, "i", 1);
865 if (mode & SILC_CHANNEL_MODE_TOPIC)
866 strncat(string, "t", 1);
868 if (mode & SILC_CHANNEL_MODE_ULIMIT)
869 strncat(string, "l", 1);
871 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
872 strncat(string, "a", 1);
874 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
875 strncat(string, "f", 1);
877 if (mode & SILC_CHANNEL_MODE_CIPHER)
878 strncat(string, cipher, strlen(cipher));
880 if (mode & SILC_CHANNEL_MODE_HMAC)
881 strncat(string, hmac, strlen(hmac));
883 /* Rest of mode is ignored */
885 return strdup(string);
888 /* Parses channel user mode mask and returns te mode as string */
890 char *silc_client_chumode(uint32 mode)
897 memset(string, 0, sizeof(string));
899 if (mode & SILC_CHANNEL_UMODE_CHANFO)
900 strncat(string, "f", 1);
902 if (mode & SILC_CHANNEL_UMODE_CHANOP)
903 strncat(string, "o", 1);
905 return strdup(string);
908 /* Parses channel user mode and returns it as special mode character. */
910 char *silc_client_chumode_char(uint32 mode)
917 memset(string, 0, sizeof(string));
919 if (mode & SILC_CHANNEL_UMODE_CHANFO)
920 strncat(string, "*", 1);
922 if (mode & SILC_CHANNEL_UMODE_CHANOP)
923 strncat(string, "@", 1);
925 return strdup(string);
928 /* Creates fingerprint from data, usually used with SHA1 digests */
930 char *silc_fingerprint(const unsigned char *data, uint32 data_len)
932 char fingerprint[64], *cp;
935 memset(fingerprint, 0, sizeof(fingerprint));
937 for (i = 0; i < data_len; i++) {
938 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
941 if ((i + 1) % 2 == 0)
942 snprintf(cp++, sizeof(fingerprint), " ");
944 if ((i + 1) % 10 == 0)
945 snprintf(cp++, sizeof(fingerprint), " ");
948 if ((i + 1) % 2 == 0)
950 if ((i + 1) % 10 == 0)
953 return strdup(fingerprint);