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 (strchr(string, '@')) {
421 tlen = strcspn(string, "@");
424 *left = silc_calloc(tlen + 1, sizeof(char));
425 memcpy(*left, string, tlen);
429 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
430 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
434 *left = strdup(string);
440 /* Parses command line. At most `max_args' is taken. Rest of the line
441 will be allocated as the last argument if there are more than `max_args'
442 arguments in the line. Note that the command name is counted as one
443 argument and is saved. */
445 void silc_parse_command_line(unsigned char *buffer,
446 unsigned char ***parsed,
447 uint32 **parsed_lens,
448 uint32 **parsed_types,
454 const char *cp = buffer;
457 *parsed = silc_calloc(1, sizeof(**parsed));
458 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
460 /* Get the command first */
461 len = strcspn(cp, " ");
462 tmp = silc_to_upper((char *)cp);
463 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
464 memcpy((*parsed)[0], tmp, len);
466 (*parsed_lens)[0] = len;
472 /* Parse arguments */
473 if (strchr(cp, ' ') || strlen(cp) != 0) {
474 for (i = 1; i < max_args; i++) {
476 if (i != max_args - 1)
477 len = strcspn(cp, " ");
480 while (len && cp[len - 1] == ' ')
485 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
486 *parsed_lens = silc_realloc(*parsed_lens,
487 sizeof(**parsed_lens) * (argc + 1));
488 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
489 memcpy((*parsed)[argc], cp, len);
490 (*parsed_lens)[argc] = len;
502 /* Save argument types. Protocol defines all argument types but
503 this implementation makes sure that they are always in correct
504 order hence this simple code. */
505 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
506 for (i = 0; i < argc; i++)
507 (*parsed_types)[i] = i;
512 /* Formats arguments to a string and returns it after allocating memory
513 for it. It must be remembered to free it later. */
515 char *silc_format(char *fmt, ...)
518 static char buf[8192];
520 memset(buf, 0, sizeof(buf));
522 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
528 /* Renders ID to suitable to print for example to log file. */
530 static char rid[256];
532 char *silc_id_render(void *id, uint16 type)
535 unsigned char tmps[2];
537 memset(rid, 0, sizeof(rid));
541 SilcServerID *server_id = (SilcServerID *)id;
542 if (server_id->ip.data_len > 4) {
544 struct in6_addr ipv6;
545 memmove(&ipv6, server_id->ip.data, sizeof(ipv6));
546 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
551 memmove(&ipv4.s_addr, server_id->ip.data, 4);
552 strcat(rid, inet_ntoa(ipv4));
555 memset(tmp, 0, sizeof(tmp));
556 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
558 SILC_PUT16_MSB(server_id->rnd, tmps);
559 memset(tmp, 0, sizeof(tmp));
560 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
566 SilcClientID *client_id = (SilcClientID *)id;
567 if (client_id->ip.data_len > 4) {
569 struct in6_addr ipv6;
570 memmove(&ipv6, client_id->ip.data, sizeof(ipv6));
571 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
576 memmove(&ipv4.s_addr, client_id->ip.data, 4);
577 strcat(rid, inet_ntoa(ipv4));
580 memset(tmp, 0, sizeof(tmp));
581 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
583 memset(tmp, 0, sizeof(tmp));
584 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
585 client_id->hash[0], client_id->hash[1],
586 client_id->hash[2], client_id->hash[3]);
590 case SILC_ID_CHANNEL:
592 SilcChannelID *channel_id = (SilcChannelID *)id;
593 if (channel_id->ip.data_len > 4) {
595 struct in6_addr ipv6;
596 memmove(&ipv6, channel_id->ip.data, sizeof(ipv6));
597 if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
602 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
603 strcat(rid, inet_ntoa(ipv4));
606 memset(tmp, 0, sizeof(tmp));
607 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
609 SILC_PUT16_MSB(channel_id->rnd, tmps);
610 memset(tmp, 0, sizeof(tmp));
611 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
620 /* Compares two strings. Strings may include wildcards * and ?.
621 Returns TRUE if strings match. */
623 int silc_string_compare(char *string1, char *string2)
626 int slen1 = strlen(string1);
627 int slen2 = strlen(string2);
628 char *tmpstr1, *tmpstr2;
630 if (!string1 || !string2)
633 /* See if they are same already */
634 if (!strncmp(string1, string2, strlen(string2)))
638 if (!strchr(string1, '*'))
641 /* Take copies of the original strings as we will change them */
642 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
643 memcpy(tmpstr1, string1, slen1);
644 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
645 memcpy(tmpstr2, string2, slen2);
647 for (i = 0; i < slen1; i++) {
649 /* * wildcard. Only one * wildcard is possible. */
650 if (tmpstr1[i] == '*')
651 if (!strncmp(tmpstr1, tmpstr2, i)) {
652 memset(tmpstr2, 0, slen2);
653 strncpy(tmpstr2, tmpstr1, i);
658 if (tmpstr1[i] == '?') {
659 if (!strncmp(tmpstr1, tmpstr2, i)) {
660 if (!(slen1 < i + 1))
661 if (tmpstr1[i + 1] != '?' &&
662 tmpstr1[i + 1] != tmpstr2[i + 1])
665 if (!(slen1 < slen2))
671 /* if using *, remove it */
672 if (strchr(tmpstr1, '*'))
673 *strchr(tmpstr1, '*') = 0;
675 if (!strcmp(tmpstr1, tmpstr2)) {
676 memset(tmpstr1, 0, slen1);
677 memset(tmpstr2, 0, slen2);
683 memset(tmpstr1, 0, slen1);
684 memset(tmpstr2, 0, slen2);
690 /* Basic has function to hash strings. May be used with the SilcHashTable.
691 Note that this lowers the characters of the string (with tolower()) so
692 this is used usually with nicknames, channel and server names to provide
693 case insensitive keys. */
695 uint32 silc_hash_string(void *key, void *user_context)
697 char *s = (char *)key;
701 h = (h << 4) + tolower(*s);
702 if ((g = h & 0xf0000000)) {
712 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
714 uint32 silc_hash_uint(void *key, void *user_context)
716 return *(uint32 *)key;
719 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
721 uint32 silc_hash_ptr(void *key, void *user_context)
726 /* Hash a ID. The `user_context' is the ID type. */
728 uint32 silc_hash_id(void *key, void *user_context)
730 SilcIdType id_type = (SilcIdType)(uint32)user_context;
737 SilcClientID *id = (SilcClientID *)key;
740 /* The client ID is hashed by hashing the hash of the ID
741 (which is a truncated MD5 hash of the nickname) so that we
742 can access the entry from the cache with both Client ID but
743 with just a hash from the ID as well. */
745 for (i = 0; i < sizeof(id->hash); i++) {
746 h = (h << 4) + id->hash[i];
747 if ((g = h & 0xf0000000)) {
758 SilcServerID *id = (SilcServerID *)key;
760 h = id->port * id->rnd;
761 for (i = 0; i < id->ip.data_len; i++)
767 case SILC_ID_CHANNEL:
769 SilcChannelID *id = (SilcChannelID *)key;
771 h = id->port * id->rnd;
772 for (i = 0; i < id->ip.data_len; i++)
785 /* Hash binary data. The `user_context' is the data length. */
787 uint32 silc_hash_data(void *key, void *user_context)
789 uint32 len = (uint32)user_context, h = 0;
790 unsigned char *data = (unsigned char *)key;
793 h = (data[0] * data[len - 1] + 1) * len;
794 for (i = 0; i < len; i++)
800 /* Compares two strings. May be used as SilcHashTable comparison function. */
802 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
804 return !strcasecmp((char *)key1, (char *)key2);
807 /* Compares two ID's. May be used as SilcHashTable comparison function.
808 The Client ID's compares only the hash of the Client ID not any other
809 part of the Client ID. Other ID's are fully compared. */
811 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
813 SilcIdType id_type = (SilcIdType)(uint32)user_context;
814 return (id_type == SILC_ID_CLIENT ?
815 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
816 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
819 /* Compare two Client ID's entirely and not just the hash from the ID. */
821 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
823 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
826 /* Compares binary data. May be used as SilcHashTable comparison function. */
828 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
830 uint32 len = (uint32)user_context;
831 return !memcmp(key1, key2, len);
834 /* Parses mode mask and returns the mode as string. */
836 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
843 memset(string, 0, sizeof(string));
845 if (mode & SILC_CHANNEL_MODE_PRIVATE)
846 strncat(string, "p", 1);
848 if (mode & SILC_CHANNEL_MODE_SECRET)
849 strncat(string, "s", 1);
851 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
852 strncat(string, "k", 1);
854 if (mode & SILC_CHANNEL_MODE_INVITE)
855 strncat(string, "i", 1);
857 if (mode & SILC_CHANNEL_MODE_TOPIC)
858 strncat(string, "t", 1);
860 if (mode & SILC_CHANNEL_MODE_ULIMIT)
861 strncat(string, "l", 1);
863 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
864 strncat(string, "a", 1);
866 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
867 strncat(string, "f", 1);
869 if (mode & SILC_CHANNEL_MODE_CIPHER)
870 strncat(string, cipher, strlen(cipher));
872 if (mode & SILC_CHANNEL_MODE_HMAC)
873 strncat(string, hmac, strlen(hmac));
875 /* Rest of mode is ignored */
877 return strdup(string);
880 /* Parses channel user mode mask and returns te mode as string */
882 char *silc_client_chumode(uint32 mode)
889 memset(string, 0, sizeof(string));
891 if (mode & SILC_CHANNEL_UMODE_CHANFO)
892 strncat(string, "f", 1);
894 if (mode & SILC_CHANNEL_UMODE_CHANOP)
895 strncat(string, "o", 1);
897 return strdup(string);
900 /* Parses channel user mode and returns it as special mode character. */
902 char *silc_client_chumode_char(uint32 mode)
909 memset(string, 0, sizeof(string));
911 if (mode & SILC_CHANNEL_UMODE_CHANFO)
912 strncat(string, "*", 1);
914 if (mode & SILC_CHANNEL_UMODE_CHANOP)
915 strncat(string, "@", 1);
917 return strdup(string);
920 /* Creates fingerprint from data, usually used with SHA1 digests */
922 char *silc_fingerprint(const unsigned char *data, uint32 data_len)
924 char fingerprint[64], *cp;
927 memset(fingerprint, 0, sizeof(fingerprint));
929 for (i = 0; i < data_len; i++) {
930 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
933 if ((i + 1) % 2 == 0)
934 snprintf(cp++, sizeof(fingerprint), " ");
936 if ((i + 1) % 10 == 0)
937 snprintf(cp++, sizeof(fingerprint), " ");
940 if ((i + 1) % 2 == 0)
942 if ((i + 1) % 10 == 0)
945 return strdup(fingerprint);