5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * These are general utility functions that doesn't belong to any specific
26 #include "silcincludes.h"
28 /* Opens a file indicated by the filename `filename' with flags indicated
31 int silc_file_open(const char *filename, int flags)
35 fd = open(filename, flags, 0600);
40 /* Reads data from file descriptor `fd' to `buf'. */
42 int silc_file_read(int fd, unsigned char *buf, uint32 buf_len)
44 return read(fd, (void *)buf, buf_len);
47 /* Writes `buffer' of length of `len' to file descriptor `fd. */
49 int silc_file_write(int fd, const char *buffer, uint32 len)
51 return write(fd, (const void *)buffer, len);
54 /* Closes file descriptor */
56 int silc_file_close(int fd)
61 /* Writes a buffer to the file. */
63 int silc_file_writefile(const char *filename, const char *buffer, uint32 len)
67 if ((fd = creat(filename, 0644)) == -1) {
68 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
73 if ((write(fd, buffer, len)) == -1) {
74 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
84 /* Writes a buffer to the file. If the file is created specific mode is
87 int silc_file_writefile_mode(const char *filename, const char *buffer,
92 if ((fd = creat(filename, mode)) == -1) {
93 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
98 if ((write(fd, buffer, len)) == -1) {
99 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
109 /* Reads a file to a buffer. The allocated buffer is returned. Length of
110 the file read is returned to the return_len argument. */
112 char *silc_file_readfile(const char *filename, uint32 *return_len)
118 fd = silc_file_open(filename, O_RDONLY);
122 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
126 filelen = lseek(fd, (off_t)0L, SEEK_END);
131 if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
137 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
142 buffer = silc_calloc(filelen + 1, sizeof(char));
144 if ((read(fd, buffer, filelen)) == -1) {
145 memset(buffer, 0, sizeof(buffer));
147 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
153 buffer[filelen] = EOF;
156 *return_len = filelen;
161 /* Returns files size. Returns 0 on error. */
163 uint64 silc_file_size(const char *filename)
169 ret = lstat(filename, &stats);
171 ret = stat(filename, &stats);
\r
176 return (uint64)stats.st_size;
179 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
180 This doesn't remove the newline sign from the destination buffer. The
181 argument begin is returned and should be passed again for the function. */
183 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
185 static int start = 0;
188 memset(dest, 0, destlen);
194 for ( ; start <= srclen; i++, start++) {
198 dest[i] = src[start];
211 /* Checks line for illegal characters. Return -1 when illegal character
212 were found. This is used to check for bad lines when reading data from
213 for example a configuration file. */
215 int silc_check_line(char *buf)
217 /* Illegal characters in line */
218 if (strchr(buf, '#')) return -1;
219 if (strchr(buf, '\'')) return -1;
220 if (strchr(buf, '\\')) return -1;
221 if (strchr(buf, '\r')) return -1;
222 if (strchr(buf, '\a')) return -1;
223 if (strchr(buf, '\b')) return -1;
224 if (strchr(buf, '\f')) return -1;
233 /* Returns current time as string. */
235 char *silc_get_time()
240 curtime = time(NULL);
241 return_time = ctime(&curtime);
242 return_time[strlen(return_time) - 1] = '\0';
247 /* Converts string to capital characters */
249 char *silc_to_upper(char *string)
252 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
254 for (i = 0; i < strlen(string); i++)
255 ret[i] = toupper(string[i]);
260 static unsigned char pem_enc[64] =
261 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
263 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
264 data string. Note: This is originally public domain code and is
267 char *silc_encode_pem(unsigned char *data, uint32 len)
270 uint32 bits, c, char_count;
277 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
279 for (i = 0; i < len; i++) {
284 if (char_count == 3) {
285 pem[j++] = pem_enc[bits >> 18];
286 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
287 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
288 pem[j++] = pem_enc[bits & 0x3f];
296 if (char_count != 0) {
297 bits <<= 16 - (8 * char_count);
298 pem[j++] = pem_enc[bits >> 18];
299 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
301 if (char_count == 1) {
305 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
313 /* Same as above but puts newline ('\n') every 72 characters. */
315 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
321 pem = silc_encode_pem(data, data_len);
324 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
326 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
341 /* Decodes PEM into data. Returns the decoded data. Note: This is
342 originally public domain code and is still PD. */
344 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
348 uint32 len, c, char_count, bits;
350 static char ialpha[256], decoder[256];
352 for (i = 64 - 1; i >= 0; i--) {
353 ialpha[pem_enc[i]] = 1;
354 decoder[pem_enc[i]] = i;
366 data = silc_calloc(((len * 6) / 8), sizeof(*data));
368 for (i = 0; i < len; i++) {
374 if (c > 127 || !ialpha[c])
380 if (char_count == 4) {
381 data[j++] = bits >> 16;
382 data[j++] = (bits >> 8) & 0xff;
383 data[j++] = bits & 0xff;
397 data[j++] = bits >> 10;
400 data[j++] = bits >> 16;
401 data[j++] = (bits >> 8) & 0xff;
411 /* Parse userfqdn string which is in user@fqdn format */
413 bool silc_parse_userfqdn(const char *string, char **left, char **right)
420 if (string[0] == '@') {
422 *left = strdup(string);
426 if (strchr(string, '@')) {
427 tlen = strcspn(string, "@");
430 *left = silc_calloc(tlen + 1, sizeof(char));
431 memcpy(*left, string, tlen);
435 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
436 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
440 *left = strdup(string);
446 /* Parses command line. At most `max_args' is taken. Rest of the line
447 will be allocated as the last argument if there are more than `max_args'
448 arguments in the line. Note that the command name is counted as one
449 argument and is saved. */
451 void silc_parse_command_line(unsigned char *buffer,
452 unsigned char ***parsed,
453 uint32 **parsed_lens,
454 uint32 **parsed_types,
460 const char *cp = buffer;
463 *parsed = silc_calloc(1, sizeof(**parsed));
464 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
466 /* Get the command first */
467 len = strcspn(cp, " ");
468 tmp = silc_to_upper((char *)cp);
469 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
470 memcpy((*parsed)[0], tmp, len);
472 (*parsed_lens)[0] = len;
478 /* Parse arguments */
479 if (strchr(cp, ' ') || strlen(cp) != 0) {
480 for (i = 1; i < max_args; i++) {
482 if (i != max_args - 1)
483 len = strcspn(cp, " ");
486 while (len && cp[len - 1] == ' ')
491 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
492 *parsed_lens = silc_realloc(*parsed_lens,
493 sizeof(**parsed_lens) * (argc + 1));
494 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
495 memcpy((*parsed)[argc], cp, len);
496 (*parsed_lens)[argc] = len;
508 /* Save argument types. Protocol defines all argument types but
509 this implementation makes sure that they are always in correct
510 order hence this simple code. */
511 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
512 for (i = 0; i < argc; i++)
513 (*parsed_types)[i] = i;
518 /* Formats arguments to a string and returns it after allocating memory
519 for it. It must be remembered to free it later. */
521 char *silc_format(char *fmt, ...)
524 static char buf[8192];
526 memset(buf, 0, sizeof(buf));
528 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
534 /* Renders ID to suitable to print for example to log file. */
536 static char rid[256];
538 char *silc_id_render(void *id, uint16 type)
541 unsigned char tmps[2];
543 memset(rid, 0, sizeof(rid));
547 SilcServerID *server_id = (SilcServerID *)id;
548 if (server_id->ip.data_len > 4) {
550 struct in6_addr ipv6;
551 memmove(&ipv6, server_id->ip.data, sizeof(ipv6));
552 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
557 memmove(&ipv4.s_addr, server_id->ip.data, 4);
558 strcat(rid, inet_ntoa(ipv4));
561 memset(tmp, 0, sizeof(tmp));
562 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
564 SILC_PUT16_MSB(server_id->rnd, tmps);
565 memset(tmp, 0, sizeof(tmp));
566 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
572 SilcClientID *client_id = (SilcClientID *)id;
573 if (client_id->ip.data_len > 4) {
575 struct in6_addr ipv6;
576 memmove(&ipv6, client_id->ip.data, sizeof(ipv6));
577 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
582 memmove(&ipv4.s_addr, client_id->ip.data, 4);
583 strcat(rid, inet_ntoa(ipv4));
586 memset(tmp, 0, sizeof(tmp));
587 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
589 memset(tmp, 0, sizeof(tmp));
590 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
591 client_id->hash[0], client_id->hash[1],
592 client_id->hash[2], client_id->hash[3]);
596 case SILC_ID_CHANNEL:
598 SilcChannelID *channel_id = (SilcChannelID *)id;
599 if (channel_id->ip.data_len > 4) {
601 struct in6_addr ipv6;
602 memmove(&ipv6, channel_id->ip.data, sizeof(ipv6));
603 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
608 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
609 strcat(rid, inet_ntoa(ipv4));
612 memset(tmp, 0, sizeof(tmp));
613 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
615 SILC_PUT16_MSB(channel_id->rnd, tmps);
616 memset(tmp, 0, sizeof(tmp));
617 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
626 /* Compares two strings. Strings may include wildcards * and ?.
627 Returns TRUE if strings match. */
629 int silc_string_compare(char *string1, char *string2)
632 int slen1 = strlen(string1);
633 int slen2 = strlen(string2);
634 char *tmpstr1, *tmpstr2;
636 if (!string1 || !string2)
639 /* See if they are same already */
640 if (!strncmp(string1, string2, strlen(string2)))
644 if (!strchr(string1, '*'))
647 /* Take copies of the original strings as we will change them */
648 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
649 memcpy(tmpstr1, string1, slen1);
650 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
651 memcpy(tmpstr2, string2, slen2);
653 for (i = 0; i < slen1; i++) {
655 /* * wildcard. Only one * wildcard is possible. */
656 if (tmpstr1[i] == '*')
657 if (!strncmp(tmpstr1, tmpstr2, i)) {
658 memset(tmpstr2, 0, slen2);
659 strncpy(tmpstr2, tmpstr1, i);
664 if (tmpstr1[i] == '?') {
665 if (!strncmp(tmpstr1, tmpstr2, i)) {
666 if (!(slen1 < i + 1))
667 if (tmpstr1[i + 1] != '?' &&
668 tmpstr1[i + 1] != tmpstr2[i + 1])
671 if (!(slen1 < slen2))
677 /* if using *, remove it */
678 if (strchr(tmpstr1, '*'))
679 *strchr(tmpstr1, '*') = 0;
681 if (!strcmp(tmpstr1, tmpstr2)) {
682 memset(tmpstr1, 0, slen1);
683 memset(tmpstr2, 0, slen2);
689 memset(tmpstr1, 0, slen1);
690 memset(tmpstr2, 0, slen2);
696 /* Basic has function to hash strings. May be used with the SilcHashTable.
697 Note that this lowers the characters of the string (with tolower()) so
698 this is used usually with nicknames, channel and server names to provide
699 case insensitive keys. */
701 uint32 silc_hash_string(void *key, void *user_context)
703 char *s = (char *)key;
707 h = (h << 4) + tolower(*s);
708 if ((g = h & 0xf0000000)) {
718 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
720 uint32 silc_hash_uint(void *key, void *user_context)
722 return *(uint32 *)key;
725 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
727 uint32 silc_hash_ptr(void *key, void *user_context)
732 /* Hash a ID. The `user_context' is the ID type. */
734 uint32 silc_hash_id(void *key, void *user_context)
736 SilcIdType id_type = (SilcIdType)(uint32)user_context;
743 SilcClientID *id = (SilcClientID *)key;
746 /* The client ID is hashed by hashing the hash of the ID
747 (which is a truncated MD5 hash of the nickname) so that we
748 can access the entry from the cache with both Client ID but
749 with just a hash from the ID as well. */
751 for (i = 0; i < sizeof(id->hash); i++) {
752 h = (h << 4) + id->hash[i];
753 if ((g = h & 0xf0000000)) {
764 SilcServerID *id = (SilcServerID *)key;
766 h = id->port * id->rnd;
767 for (i = 0; i < id->ip.data_len; i++)
773 case SILC_ID_CHANNEL:
775 SilcChannelID *id = (SilcChannelID *)key;
777 h = id->port * id->rnd;
778 for (i = 0; i < id->ip.data_len; i++)
791 /* Hash binary data. The `user_context' is the data length. */
793 uint32 silc_hash_data(void *key, void *user_context)
795 uint32 len = (uint32)user_context, h = 0;
796 unsigned char *data = (unsigned char *)key;
799 h = (data[0] * data[len - 1] + 1) * len;
800 for (i = 0; i < len; i++)
806 /* Compares two strings. May be used as SilcHashTable comparison function. */
808 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
810 return !strcasecmp((char *)key1, (char *)key2);
813 /* Compares two ID's. May be used as SilcHashTable comparison function.
814 The Client ID's compares only the hash of the Client ID not any other
815 part of the Client ID. Other ID's are fully compared. */
817 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
819 SilcIdType id_type = (SilcIdType)(uint32)user_context;
820 return (id_type == SILC_ID_CLIENT ?
821 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
822 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
825 /* Compare two Client ID's entirely and not just the hash from the ID. */
827 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
829 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
832 /* Compares binary data. May be used as SilcHashTable comparison function. */
834 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
836 uint32 len = (uint32)user_context;
837 return !memcmp(key1, key2, len);
840 /* Parses mode mask and returns the mode as string. */
842 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
849 memset(string, 0, sizeof(string));
851 if (mode & SILC_CHANNEL_MODE_PRIVATE)
852 strncat(string, "p", 1);
854 if (mode & SILC_CHANNEL_MODE_SECRET)
855 strncat(string, "s", 1);
857 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
858 strncat(string, "k", 1);
860 if (mode & SILC_CHANNEL_MODE_INVITE)
861 strncat(string, "i", 1);
863 if (mode & SILC_CHANNEL_MODE_TOPIC)
864 strncat(string, "t", 1);
866 if (mode & SILC_CHANNEL_MODE_ULIMIT)
867 strncat(string, "l", 1);
869 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
870 strncat(string, "a", 1);
872 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
873 strncat(string, "f", 1);
875 if (mode & SILC_CHANNEL_MODE_CIPHER)
876 strncat(string, cipher, strlen(cipher));
878 if (mode & SILC_CHANNEL_MODE_HMAC)
879 strncat(string, hmac, strlen(hmac));
881 /* Rest of mode is ignored */
883 return strdup(string);
886 /* Parses channel user mode mask and returns te mode as string */
888 char *silc_client_chumode(uint32 mode)
895 memset(string, 0, sizeof(string));
897 if (mode & SILC_CHANNEL_UMODE_CHANFO)
898 strncat(string, "f", 1);
900 if (mode & SILC_CHANNEL_UMODE_CHANOP)
901 strncat(string, "o", 1);
903 return strdup(string);
906 /* Parses channel user mode and returns it as special mode character. */
908 char *silc_client_chumode_char(uint32 mode)
915 memset(string, 0, sizeof(string));
917 if (mode & SILC_CHANNEL_UMODE_CHANFO)
918 strncat(string, "*", 1);
920 if (mode & SILC_CHANNEL_UMODE_CHANOP)
921 strncat(string, "@", 1);
923 return strdup(string);
926 /* Creates fingerprint from data, usually used with SHA1 digests */
928 char *silc_fingerprint(const unsigned char *data, uint32 data_len)
930 char fingerprint[64], *cp;
933 memset(fingerprint, 0, sizeof(fingerprint));
935 for (i = 0; i < data_len; i++) {
936 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
939 if ((i + 1) % 2 == 0)
940 snprintf(cp++, sizeof(fingerprint), " ");
942 if ((i + 1) % 10 == 0)
943 snprintf(cp++, sizeof(fingerprint), " ");
946 if ((i + 1) % 2 == 0)
948 if ((i + 1) % 10 == 0)
951 return strdup(fingerprint);