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;
544 if (server_id->ip.data_len > 4) {
547 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
548 strcat(rid, inet_ntoa(ipv4));
551 memset(tmp, 0, sizeof(tmp));
552 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
554 SILC_PUT16_MSB(server_id->rnd, tmps);
555 memset(tmp, 0, sizeof(tmp));
556 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
562 SilcClientID *client_id = (SilcClientID *)id;
565 if (client_id->ip.data_len > 4) {
568 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
569 strcat(rid, inet_ntoa(ipv4));
572 memset(tmp, 0, sizeof(tmp));
573 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
575 memset(tmp, 0, sizeof(tmp));
576 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
577 client_id->hash[0], client_id->hash[1],
578 client_id->hash[2], client_id->hash[3]);
582 case SILC_ID_CHANNEL:
584 SilcChannelID *channel_id = (SilcChannelID *)id;
587 if (channel_id->ip.data_len > 4) {
590 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
591 strcat(rid, inet_ntoa(ipv4));
594 memset(tmp, 0, sizeof(tmp));
595 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
597 SILC_PUT16_MSB(channel_id->rnd, tmps);
598 memset(tmp, 0, sizeof(tmp));
599 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
608 /* Compares two strings. Strings may include wildcards * and ?.
609 Returns TRUE if strings match. */
611 int silc_string_compare(char *string1, char *string2)
614 int slen1 = strlen(string1);
615 int slen2 = strlen(string2);
616 char *tmpstr1, *tmpstr2;
618 if (!string1 || !string2)
621 /* See if they are same already */
622 if (!strncmp(string1, string2, strlen(string2)))
626 if (!strchr(string1, '*'))
629 /* Take copies of the original strings as we will change them */
630 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
631 memcpy(tmpstr1, string1, slen1);
632 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
633 memcpy(tmpstr2, string2, slen2);
635 for (i = 0; i < slen1; i++) {
637 /* * wildcard. Only one * wildcard is possible. */
638 if (tmpstr1[i] == '*')
639 if (!strncmp(tmpstr1, tmpstr2, i)) {
640 memset(tmpstr2, 0, slen2);
641 strncpy(tmpstr2, tmpstr1, i);
646 if (tmpstr1[i] == '?') {
647 if (!strncmp(tmpstr1, tmpstr2, i)) {
648 if (!(slen1 < i + 1))
649 if (tmpstr1[i + 1] != '?' &&
650 tmpstr1[i + 1] != tmpstr2[i + 1])
653 if (!(slen1 < slen2))
659 /* if using *, remove it */
660 if (strchr(tmpstr1, '*'))
661 *strchr(tmpstr1, '*') = 0;
663 if (!strcmp(tmpstr1, tmpstr2)) {
664 memset(tmpstr1, 0, slen1);
665 memset(tmpstr2, 0, slen2);
671 memset(tmpstr1, 0, slen1);
672 memset(tmpstr2, 0, slen2);
678 /* Basic has function to hash strings. May be used with the SilcHashTable.
679 Note that this lowers the characters of the string (with tolower()) so
680 this is used usually with nicknames, channel and server names to provide
681 case insensitive keys. */
683 uint32 silc_hash_string(void *key, void *user_context)
685 char *s = (char *)key;
689 h = (h << 4) + tolower(*s);
690 if ((g = h & 0xf0000000)) {
700 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
702 uint32 silc_hash_uint(void *key, void *user_context)
704 return *(uint32 *)key;
707 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
709 uint32 silc_hash_ptr(void *key, void *user_context)
714 /* Hash a ID. The `user_context' is the ID type. */
716 uint32 silc_hash_id(void *key, void *user_context)
718 SilcIdType id_type = (SilcIdType)(uint32)user_context;
725 SilcClientID *id = (SilcClientID *)key;
728 /* The client ID is hashed by hashing the hash of the ID
729 (which is a truncated MD5 hash of the nickname) so that we
730 can access the entry from the cache with both Client ID but
731 with just a hash from the ID as well. */
733 for (i = 0; i < sizeof(id->hash); i++) {
734 h = (h << 4) + id->hash[i];
735 if ((g = h & 0xf0000000)) {
746 SilcServerID *id = (SilcServerID *)key;
748 h = id->port * id->rnd;
749 for (i = 0; i < id->ip.data_len; i++)
755 case SILC_ID_CHANNEL:
757 SilcChannelID *id = (SilcChannelID *)key;
759 h = id->port * id->rnd;
760 for (i = 0; i < id->ip.data_len; i++)
773 /* Hash binary data. The `user_context' is the data length. */
775 uint32 silc_hash_data(void *key, void *user_context)
777 uint32 len = (uint32)user_context, h = 0;
778 unsigned char *data = (unsigned char *)key;
781 h = (data[0] * data[len - 1] + 1) * len;
782 for (i = 0; i < len; i++)
788 /* Compares two strings. May be used as SilcHashTable comparison function. */
790 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
792 return !strcasecmp((char *)key1, (char *)key2);
795 /* Compares two ID's. May be used as SilcHashTable comparison function.
796 The Client ID's compares only the hash of the Client ID not any other
797 part of the Client ID. Other ID's are fully compared. */
799 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
801 SilcIdType id_type = (SilcIdType)(uint32)user_context;
802 return (id_type == SILC_ID_CLIENT ?
803 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
804 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
807 /* Compare two Client ID's entirely and not just the hash from the ID. */
809 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
811 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
814 /* Compares binary data. May be used as SilcHashTable comparison function. */
816 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
818 uint32 len = (uint32)user_context;
819 return !memcmp(key1, key2, len);
822 /* Parses mode mask and returns the mode as string. */
824 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
831 memset(string, 0, sizeof(string));
833 if (mode & SILC_CHANNEL_MODE_PRIVATE)
834 strncat(string, "p", 1);
836 if (mode & SILC_CHANNEL_MODE_SECRET)
837 strncat(string, "s", 1);
839 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
840 strncat(string, "k", 1);
842 if (mode & SILC_CHANNEL_MODE_INVITE)
843 strncat(string, "i", 1);
845 if (mode & SILC_CHANNEL_MODE_TOPIC)
846 strncat(string, "t", 1);
848 if (mode & SILC_CHANNEL_MODE_ULIMIT)
849 strncat(string, "l", 1);
851 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
852 strncat(string, "a", 1);
854 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
855 strncat(string, "f", 1);
857 if (mode & SILC_CHANNEL_MODE_CIPHER)
858 strncat(string, cipher, strlen(cipher));
860 if (mode & SILC_CHANNEL_MODE_HMAC)
861 strncat(string, hmac, strlen(hmac));
863 /* Rest of mode is ignored */
865 return strdup(string);
868 /* Parses channel user mode mask and returns te mode as string */
870 char *silc_client_chumode(uint32 mode)
877 memset(string, 0, sizeof(string));
879 if (mode & SILC_CHANNEL_UMODE_CHANFO)
880 strncat(string, "f", 1);
882 if (mode & SILC_CHANNEL_UMODE_CHANOP)
883 strncat(string, "o", 1);
885 return strdup(string);
888 /* Parses channel user mode and returns it as special mode character. */
890 char *silc_client_chumode_char(uint32 mode)
897 memset(string, 0, sizeof(string));
899 if (mode & SILC_CHANNEL_UMODE_CHANFO)
900 strncat(string, "*", 1);
902 if (mode & SILC_CHANNEL_UMODE_CHANOP)
903 strncat(string, "@", 1);
905 return strdup(string);