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);
\r
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)
631 int slen1 = strlen(string1);
632 int slen2 = strlen(string2);
633 char *tmpstr1, *tmpstr2;
635 if (!string1 || !string2)
638 /* See if they are same already */
639 if (!strncmp(string1, string2, strlen(string2)))
643 if (!strchr(string1, '*'))
646 /* Take copies of the original strings as we will change them */
647 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
648 memcpy(tmpstr1, string1, slen1);
649 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
650 memcpy(tmpstr2, string2, slen2);
652 for (i = 0; i < slen1; i++) {
654 /* * wildcard. Only one * wildcard is possible. */
655 if (tmpstr1[i] == '*')
656 if (!strncmp(tmpstr1, tmpstr2, i)) {
657 memset(tmpstr2, 0, slen2);
658 strncpy(tmpstr2, tmpstr1, i);
663 if (tmpstr1[i] == '?') {
664 if (!strncmp(tmpstr1, tmpstr2, i)) {
665 if (!(slen1 < i + 1))
666 if (tmpstr1[i + 1] != '?' &&
667 tmpstr1[i + 1] != tmpstr2[i + 1])
670 if (!(slen1 < slen2))
676 /* if using *, remove it */
677 if (strchr(tmpstr1, '*'))
678 *strchr(tmpstr1, '*') = 0;
680 if (!strcmp(tmpstr1, tmpstr2)) {
681 memset(tmpstr1, 0, slen1);
682 memset(tmpstr2, 0, slen2);
688 memset(tmpstr1, 0, slen1);
689 memset(tmpstr2, 0, slen2);
695 /* Basic has function to hash strings. May be used with the SilcHashTable.
696 Note that this lowers the characters of the string (with tolower()) so
697 this is used usually with nicknames, channel and server names to provide
698 case insensitive keys. */
700 uint32 silc_hash_string(void *key, void *user_context)
702 char *s = (char *)key;
706 h = (h << 4) + tolower(*s);
707 if ((g = h & 0xf0000000)) {
717 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
719 uint32 silc_hash_uint(void *key, void *user_context)
721 return *(uint32 *)key;
724 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
726 uint32 silc_hash_ptr(void *key, void *user_context)
731 /* Hash a ID. The `user_context' is the ID type. */
733 uint32 silc_hash_id(void *key, void *user_context)
735 SilcIdType id_type = (SilcIdType)(uint32)user_context;
742 SilcClientID *id = (SilcClientID *)key;
745 /* The client ID is hashed by hashing the hash of the ID
746 (which is a truncated MD5 hash of the nickname) so that we
747 can access the entry from the cache with both Client ID but
748 with just a hash from the ID as well. */
750 for (i = 0; i < sizeof(id->hash); i++) {
751 h = (h << 4) + id->hash[i];
752 if ((g = h & 0xf0000000)) {
763 SilcServerID *id = (SilcServerID *)key;
765 h = id->port * id->rnd;
766 for (i = 0; i < id->ip.data_len; i++)
772 case SILC_ID_CHANNEL:
774 SilcChannelID *id = (SilcChannelID *)key;
776 h = id->port * id->rnd;
777 for (i = 0; i < id->ip.data_len; i++)
790 /* Hash binary data. The `user_context' is the data length. */
792 uint32 silc_hash_data(void *key, void *user_context)
794 uint32 len = (uint32)user_context, h = 0;
795 unsigned char *data = (unsigned char *)key;
798 h = (data[0] * data[len - 1] + 1) * len;
799 for (i = 0; i < len; i++)
805 /* Compares two strings. May be used as SilcHashTable comparison function. */
807 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
809 return !strcasecmp((char *)key1, (char *)key2);
812 /* Compares two ID's. May be used as SilcHashTable comparison function.
813 The Client ID's compares only the hash of the Client ID not any other
814 part of the Client ID. Other ID's are fully compared. */
816 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
818 SilcIdType id_type = (SilcIdType)(uint32)user_context;
819 return (id_type == SILC_ID_CLIENT ?
820 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
821 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
824 /* Compare two Client ID's entirely and not just the hash from the ID. */
826 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
828 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
831 /* Compares binary data. May be used as SilcHashTable comparison function. */
833 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
835 uint32 len = (uint32)user_context;
836 return !memcmp(key1, key2, len);
839 /* Parses mode mask and returns the mode as string. */
841 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
848 memset(string, 0, sizeof(string));
850 if (mode & SILC_CHANNEL_MODE_PRIVATE)
851 strncat(string, "p", 1);
853 if (mode & SILC_CHANNEL_MODE_SECRET)
854 strncat(string, "s", 1);
856 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
857 strncat(string, "k", 1);
859 if (mode & SILC_CHANNEL_MODE_INVITE)
860 strncat(string, "i", 1);
862 if (mode & SILC_CHANNEL_MODE_TOPIC)
863 strncat(string, "t", 1);
865 if (mode & SILC_CHANNEL_MODE_ULIMIT)
866 strncat(string, "l", 1);
868 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
869 strncat(string, "a", 1);
871 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
872 strncat(string, "f", 1);
874 if (mode & SILC_CHANNEL_MODE_CIPHER)
875 strncat(string, cipher, strlen(cipher));
877 if (mode & SILC_CHANNEL_MODE_HMAC)
878 strncat(string, hmac, strlen(hmac));
880 /* Rest of mode is ignored */
882 return strdup(string);
885 /* Parses channel user mode mask and returns te mode as string */
887 char *silc_client_chumode(uint32 mode)
894 memset(string, 0, sizeof(string));
896 if (mode & SILC_CHANNEL_UMODE_CHANFO)
897 strncat(string, "f", 1);
899 if (mode & SILC_CHANNEL_UMODE_CHANOP)
900 strncat(string, "o", 1);
902 return strdup(string);
905 /* Parses channel user mode and returns it as special mode character. */
907 char *silc_client_chumode_char(uint32 mode)
914 memset(string, 0, sizeof(string));
916 if (mode & SILC_CHANNEL_UMODE_CHANFO)
917 strncat(string, "*", 1);
919 if (mode & SILC_CHANNEL_UMODE_CHANOP)
920 strncat(string, "@", 1);
922 return strdup(string);
925 /* Creates fingerprint from data, usually used with SHA1 digests */
927 char *silc_fingerprint(const unsigned char *data, uint32 data_len)
929 char fingerprint[64], *cp;
932 memset(fingerprint, 0, sizeof(fingerprint));
934 for (i = 0; i < data_len; i++) {
935 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
938 if ((i + 1) % 2 == 0)
939 snprintf(cp++, sizeof(fingerprint), " ");
941 if ((i + 1) % 10 == 0)
942 snprintf(cp++, sizeof(fingerprint), " ");
945 if ((i + 1) % 2 == 0)
947 if ((i + 1) % 10 == 0)
950 return strdup(fingerprint);