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)
168 ret = lstat(filename, &stats);
172 return (uint64)stats.st_size;
175 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
176 This doesn't remove the newline sign from the destination buffer. The
177 argument begin is returned and should be passed again for the function. */
179 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
181 static int start = 0;
184 memset(dest, 0, destlen);
190 for ( ; start <= srclen; i++, start++) {
194 dest[i] = src[start];
207 /* Checks line for illegal characters. Return -1 when illegal character
208 were found. This is used to check for bad lines when reading data from
209 for example a configuration file. */
211 int silc_check_line(char *buf)
213 /* Illegal characters in line */
214 if (strchr(buf, '#')) return -1;
215 if (strchr(buf, '\'')) return -1;
216 if (strchr(buf, '\\')) return -1;
217 if (strchr(buf, '\r')) return -1;
218 if (strchr(buf, '\a')) return -1;
219 if (strchr(buf, '\b')) return -1;
220 if (strchr(buf, '\f')) return -1;
229 /* Returns current time as string. */
231 char *silc_get_time()
236 curtime = time(NULL);
237 return_time = ctime(&curtime);
238 return_time[strlen(return_time) - 1] = '\0';
243 /* Converts string to capital characters */
245 char *silc_to_upper(char *string)
248 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
250 for (i = 0; i < strlen(string); i++)
251 ret[i] = toupper(string[i]);
256 static unsigned char pem_enc[64] =
257 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
259 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
260 data string. Note: This is originally public domain code and is
263 char *silc_encode_pem(unsigned char *data, uint32 len)
266 uint32 bits, c, char_count;
273 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
275 for (i = 0; i < len; i++) {
280 if (char_count == 3) {
281 pem[j++] = pem_enc[bits >> 18];
282 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
283 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
284 pem[j++] = pem_enc[bits & 0x3f];
292 if (char_count != 0) {
293 bits <<= 16 - (8 * char_count);
294 pem[j++] = pem_enc[bits >> 18];
295 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
297 if (char_count == 1) {
301 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
309 /* Same as above but puts newline ('\n') every 72 characters. */
311 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
317 pem = silc_encode_pem(data, data_len);
320 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
322 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
337 /* Decodes PEM into data. Returns the decoded data. Note: This is
338 originally public domain code and is still PD. */
340 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
344 uint32 len, c, char_count, bits;
346 static char ialpha[256], decoder[256];
348 for (i = 64 - 1; i >= 0; i--) {
349 ialpha[pem_enc[i]] = 1;
350 decoder[pem_enc[i]] = i;
362 data = silc_calloc(((len * 6) / 8), sizeof(*data));
364 for (i = 0; i < len; i++) {
370 if (c > 127 || !ialpha[c])
376 if (char_count == 4) {
377 data[j++] = bits >> 16;
378 data[j++] = (bits >> 8) & 0xff;
379 data[j++] = bits & 0xff;
393 data[j++] = bits >> 10;
396 data[j++] = bits >> 16;
397 data[j++] = (bits >> 8) & 0xff;
407 /* Parse userfqdn string which is in user@fqdn format */
409 bool silc_parse_userfqdn(const char *string, char **left, char **right)
416 if (strchr(string, '@')) {
417 tlen = strcspn(string, "@");
420 *left = silc_calloc(tlen + 1, sizeof(char));
421 memcpy(*left, string, tlen);
425 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
426 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
430 *left = strdup(string);
436 /* Parses command line. At most `max_args' is taken. Rest of the line
437 will be allocated as the last argument if there are more than `max_args'
438 arguments in the line. Note that the command name is counted as one
439 argument and is saved. */
441 void silc_parse_command_line(unsigned char *buffer,
442 unsigned char ***parsed,
443 uint32 **parsed_lens,
444 uint32 **parsed_types,
450 const char *cp = buffer;
453 *parsed = silc_calloc(1, sizeof(**parsed));
454 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
456 /* Get the command first */
457 len = strcspn(cp, " ");
458 tmp = silc_to_upper((char *)cp);
459 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
460 memcpy((*parsed)[0], tmp, len);
462 (*parsed_lens)[0] = len;
468 /* Parse arguments */
469 if (strchr(cp, ' ') || strlen(cp) != 0) {
470 for (i = 1; i < max_args; i++) {
472 if (i != max_args - 1)
473 len = strcspn(cp, " ");
476 while (len && cp[len - 1] == ' ')
481 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
482 *parsed_lens = silc_realloc(*parsed_lens,
483 sizeof(**parsed_lens) * (argc + 1));
484 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
485 memcpy((*parsed)[argc], cp, len);
486 (*parsed_lens)[argc] = len;
498 /* Save argument types. Protocol defines all argument types but
499 this implementation makes sure that they are always in correct
500 order hence this simple code. */
501 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
502 for (i = 0; i < argc; i++)
503 (*parsed_types)[i] = i;
508 /* Formats arguments to a string and returns it after allocating memory
509 for it. It must be remembered to free it later. */
511 char *silc_format(char *fmt, ...)
514 static char buf[8192];
516 memset(buf, 0, sizeof(buf));
518 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
524 /* Renders ID to suitable to print for example to log file. */
526 static char rid[256];
528 char *silc_id_render(void *id, uint16 type)
531 unsigned char tmps[2];
533 memset(rid, 0, sizeof(rid));
537 SilcServerID *server_id = (SilcServerID *)id;
540 if (server_id->ip.data_len > 4) {
543 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
544 strcat(rid, inet_ntoa(ipv4));
547 memset(tmp, 0, sizeof(tmp));
548 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
550 SILC_PUT16_MSB(server_id->rnd, tmps);
551 memset(tmp, 0, sizeof(tmp));
552 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
558 SilcClientID *client_id = (SilcClientID *)id;
561 if (client_id->ip.data_len > 4) {
564 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
565 strcat(rid, inet_ntoa(ipv4));
568 memset(tmp, 0, sizeof(tmp));
569 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
571 memset(tmp, 0, sizeof(tmp));
572 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
573 client_id->hash[0], client_id->hash[1],
574 client_id->hash[2], client_id->hash[3]);
578 case SILC_ID_CHANNEL:
580 SilcChannelID *channel_id = (SilcChannelID *)id;
583 if (channel_id->ip.data_len > 4) {
586 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
587 strcat(rid, inet_ntoa(ipv4));
590 memset(tmp, 0, sizeof(tmp));
591 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
593 SILC_PUT16_MSB(channel_id->rnd, tmps);
594 memset(tmp, 0, sizeof(tmp));
595 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
604 /* Compares two strings. Strings may include wildcards * and ?.
605 Returns TRUE if strings match. */
607 int silc_string_compare(char *string1, char *string2)
610 int slen1 = strlen(string1);
611 int slen2 = strlen(string2);
612 char *tmpstr1, *tmpstr2;
614 if (!string1 || !string2)
617 /* See if they are same already */
618 if (!strncmp(string1, string2, strlen(string2)))
622 if (!strchr(string1, '*'))
625 /* Take copies of the original strings as we will change them */
626 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
627 memcpy(tmpstr1, string1, slen1);
628 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
629 memcpy(tmpstr2, string2, slen2);
631 for (i = 0; i < slen1; i++) {
633 /* * wildcard. Only one * wildcard is possible. */
634 if (tmpstr1[i] == '*')
635 if (!strncmp(tmpstr1, tmpstr2, i)) {
636 memset(tmpstr2, 0, slen2);
637 strncpy(tmpstr2, tmpstr1, i);
642 if (tmpstr1[i] == '?') {
643 if (!strncmp(tmpstr1, tmpstr2, i)) {
644 if (!(slen1 < i + 1))
645 if (tmpstr1[i + 1] != '?' &&
646 tmpstr1[i + 1] != tmpstr2[i + 1])
649 if (!(slen1 < slen2))
655 /* if using *, remove it */
656 if (strchr(tmpstr1, '*'))
657 *strchr(tmpstr1, '*') = 0;
659 if (!strcmp(tmpstr1, tmpstr2)) {
660 memset(tmpstr1, 0, slen1);
661 memset(tmpstr2, 0, slen2);
667 memset(tmpstr1, 0, slen1);
668 memset(tmpstr2, 0, slen2);
674 /* Basic has function to hash strings. May be used with the SilcHashTable.
675 Note that this lowers the characters of the string (with tolower()) so
676 this is used usually with nicknames, channel and server names to provide
677 case insensitive keys. */
679 uint32 silc_hash_string(void *key, void *user_context)
681 char *s = (char *)key;
685 h = (h << 4) + tolower(*s);
686 if ((g = h & 0xf0000000)) {
696 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
698 uint32 silc_hash_uint(void *key, void *user_context)
700 return *(uint32 *)key;
703 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
705 uint32 silc_hash_ptr(void *key, void *user_context)
710 /* Hash a ID. The `user_context' is the ID type. */
712 uint32 silc_hash_id(void *key, void *user_context)
714 SilcIdType id_type = (SilcIdType)(uint32)user_context;
721 SilcClientID *id = (SilcClientID *)key;
724 /* The client ID is hashed by hashing the hash of the ID
725 (which is a truncated MD5 hash of the nickname) so that we
726 can access the entry from the cache with both Client ID but
727 with just a hash from the ID as well. */
729 for (i = 0; i < sizeof(id->hash); i++) {
730 h = (h << 4) + id->hash[i];
731 if ((g = h & 0xf0000000)) {
742 SilcServerID *id = (SilcServerID *)key;
744 h = id->port * id->rnd;
745 for (i = 0; i < id->ip.data_len; i++)
751 case SILC_ID_CHANNEL:
753 SilcChannelID *id = (SilcChannelID *)key;
755 h = id->port * id->rnd;
756 for (i = 0; i < id->ip.data_len; i++)
769 /* Hash binary data. The `user_context' is the data length. */
771 uint32 silc_hash_data(void *key, void *user_context)
773 uint32 len = (uint32)user_context, h = 0;
774 unsigned char *data = (unsigned char *)key;
777 h = (data[0] * data[len - 1] + 1) * len;
778 for (i = 0; i < len; i++)
784 /* Compares two strings. May be used as SilcHashTable comparison function. */
786 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
788 return !strcasecmp((char *)key1, (char *)key2);
791 /* Compares two ID's. May be used as SilcHashTable comparison function.
792 The Client ID's compares only the hash of the Client ID not any other
793 part of the Client ID. Other ID's are fully compared. */
795 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
797 SilcIdType id_type = (SilcIdType)(uint32)user_context;
798 return (id_type == SILC_ID_CLIENT ?
799 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
800 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
803 /* Compare two Client ID's entirely and not just the hash from the ID. */
805 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
807 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
810 /* Compares binary data. May be used as SilcHashTable comparison function. */
812 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
814 uint32 len = (uint32)user_context;
815 return !memcmp(key1, key2, len);
818 /* Parses mode mask and returns the mode as string. */
820 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
827 memset(string, 0, sizeof(string));
829 if (mode & SILC_CHANNEL_MODE_PRIVATE)
830 strncat(string, "p", 1);
832 if (mode & SILC_CHANNEL_MODE_SECRET)
833 strncat(string, "s", 1);
835 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
836 strncat(string, "k", 1);
838 if (mode & SILC_CHANNEL_MODE_INVITE)
839 strncat(string, "i", 1);
841 if (mode & SILC_CHANNEL_MODE_TOPIC)
842 strncat(string, "t", 1);
844 if (mode & SILC_CHANNEL_MODE_ULIMIT)
845 strncat(string, "l", 1);
847 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
848 strncat(string, "a", 1);
850 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
851 strncat(string, "f", 1);
853 if (mode & SILC_CHANNEL_MODE_CIPHER)
854 strncat(string, cipher, strlen(cipher));
856 if (mode & SILC_CHANNEL_MODE_HMAC)
857 strncat(string, hmac, strlen(hmac));
859 /* Rest of mode is ignored */
861 return strdup(string);
864 /* Parses channel user mode mask and returns te mode as string */
866 char *silc_client_chumode(uint32 mode)
873 memset(string, 0, sizeof(string));
875 if (mode & SILC_CHANNEL_UMODE_CHANFO)
876 strncat(string, "f", 1);
878 if (mode & SILC_CHANNEL_UMODE_CHANOP)
879 strncat(string, "o", 1);
881 return strdup(string);
884 /* Parses channel user mode and returns it as special mode character. */
886 char *silc_client_chumode_char(uint32 mode)
893 memset(string, 0, sizeof(string));
895 if (mode & SILC_CHANNEL_UMODE_CHANFO)
896 strncat(string, "*", 1);
898 if (mode & SILC_CHANNEL_UMODE_CHANOP)
899 strncat(string, "@", 1);
901 return strdup(string);