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);
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 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
162 This doesn't remove the newline sign from the destination buffer. The
163 argument begin is returned and should be passed again for the function. */
165 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
167 static int start = 0;
170 memset(dest, 0, destlen);
176 for ( ; start <= srclen; i++, start++) {
180 dest[i] = src[start];
193 /* Checks line for illegal characters. Return -1 when illegal character
194 were found. This is used to check for bad lines when reading data from
195 for example a configuration file. */
197 int silc_check_line(char *buf)
199 /* Illegal characters in line */
200 if (strchr(buf, '#')) return -1;
201 if (strchr(buf, '\'')) return -1;
202 if (strchr(buf, '\\')) return -1;
203 if (strchr(buf, '\r')) return -1;
204 if (strchr(buf, '\a')) return -1;
205 if (strchr(buf, '\b')) return -1;
206 if (strchr(buf, '\f')) return -1;
215 /* Returns current time as string. */
217 char *silc_get_time()
222 curtime = time(NULL);
223 return_time = ctime(&curtime);
224 return_time[strlen(return_time) - 1] = '\0';
229 /* Converts string to capital characters */
231 char *silc_to_upper(char *string)
234 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
236 for (i = 0; i < strlen(string); i++)
237 ret[i] = toupper(string[i]);
242 static unsigned char pem_enc[64] =
243 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
245 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
246 data string. Note: This is originally public domain code and is
249 char *silc_encode_pem(unsigned char *data, uint32 len)
252 uint32 bits, c, char_count;
259 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
261 for (i = 0; i < len; i++) {
266 if (char_count == 3) {
267 pem[j++] = pem_enc[bits >> 18];
268 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
269 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
270 pem[j++] = pem_enc[bits & 0x3f];
278 if (char_count != 0) {
279 bits <<= 16 - (8 * char_count);
280 pem[j++] = pem_enc[bits >> 18];
281 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
283 if (char_count == 1) {
287 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
295 /* Same as above but puts newline ('\n') every 72 characters. */
297 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
303 pem = silc_encode_pem(data, data_len);
306 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
308 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
323 /* Decodes PEM into data. Returns the decoded data. Note: This is
324 originally public domain code and is still PD. */
326 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
330 uint32 len, c, char_count, bits;
332 static char ialpha[256], decoder[256];
334 for (i = 64 - 1; i >= 0; i--) {
335 ialpha[pem_enc[i]] = 1;
336 decoder[pem_enc[i]] = i;
348 data = silc_calloc(((len * 6) / 8), sizeof(*data));
350 for (i = 0; i < len; i++) {
356 if (c > 127 || !ialpha[c])
362 if (char_count == 4) {
363 data[j++] = bits >> 16;
364 data[j++] = (bits >> 8) & 0xff;
365 data[j++] = bits & 0xff;
379 data[j++] = bits >> 10;
382 data[j++] = bits >> 16;
383 data[j++] = (bits >> 8) & 0xff;
393 /* Parse userfqdn string which is in user@fqdn format */
395 bool silc_parse_userfqdn(const char *string, char **left, char **right)
402 if (strchr(string, '@')) {
403 tlen = strcspn(string, "@");
406 *left = silc_calloc(tlen + 1, sizeof(char));
407 memcpy(*left, string, tlen);
411 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
412 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
416 *left = strdup(string);
422 /* Parses command line. At most `max_args' is taken. Rest of the line
423 will be allocated as the last argument if there are more than `max_args'
424 arguments in the line. Note that the command name is counted as one
425 argument and is saved. */
427 void silc_parse_command_line(unsigned char *buffer,
428 unsigned char ***parsed,
429 uint32 **parsed_lens,
430 uint32 **parsed_types,
436 const char *cp = buffer;
439 *parsed = silc_calloc(1, sizeof(**parsed));
440 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
442 /* Get the command first */
443 len = strcspn(cp, " ");
444 tmp = silc_to_upper((char *)cp);
445 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
446 memcpy((*parsed)[0], tmp, len);
448 (*parsed_lens)[0] = len;
454 /* Parse arguments */
455 if (strchr(cp, ' ') || strlen(cp) != 0) {
456 for (i = 1; i < max_args; i++) {
458 if (i != max_args - 1)
459 len = strcspn(cp, " ");
462 while (len && cp[len - 1] == ' ')
467 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
468 *parsed_lens = silc_realloc(*parsed_lens,
469 sizeof(**parsed_lens) * (argc + 1));
470 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
471 memcpy((*parsed)[argc], cp, len);
472 (*parsed_lens)[argc] = len;
484 /* Save argument types. Protocol defines all argument types but
485 this implementation makes sure that they are always in correct
486 order hence this simple code. */
487 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
488 for (i = 0; i < argc; i++)
489 (*parsed_types)[i] = i;
494 /* Formats arguments to a string and returns it after allocating memory
495 for it. It must be remembered to free it later. */
497 char *silc_format(char *fmt, ...)
500 static char buf[8192];
502 memset(buf, 0, sizeof(buf));
504 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
510 /* Renders ID to suitable to print for example to log file. */
512 static char rid[256];
514 char *silc_id_render(void *id, uint16 type)
517 unsigned char tmps[2];
519 memset(rid, 0, sizeof(rid));
523 SilcServerID *server_id = (SilcServerID *)id;
526 if (server_id->ip.data_len > 4) {
529 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
530 strcat(rid, inet_ntoa(ipv4));
533 memset(tmp, 0, sizeof(tmp));
534 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
536 SILC_PUT16_MSB(server_id->rnd, tmps);
537 memset(tmp, 0, sizeof(tmp));
538 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
544 SilcClientID *client_id = (SilcClientID *)id;
547 if (client_id->ip.data_len > 4) {
550 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
551 strcat(rid, inet_ntoa(ipv4));
554 memset(tmp, 0, sizeof(tmp));
555 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
557 memset(tmp, 0, sizeof(tmp));
558 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
559 client_id->hash[0], client_id->hash[1],
560 client_id->hash[2], client_id->hash[3]);
564 case SILC_ID_CHANNEL:
566 SilcChannelID *channel_id = (SilcChannelID *)id;
569 if (channel_id->ip.data_len > 4) {
572 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
573 strcat(rid, inet_ntoa(ipv4));
576 memset(tmp, 0, sizeof(tmp));
577 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
579 SILC_PUT16_MSB(channel_id->rnd, tmps);
580 memset(tmp, 0, sizeof(tmp));
581 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
590 /* Compares two strings. Strings may include wildcards * and ?.
591 Returns TRUE if strings match. */
593 int silc_string_compare(char *string1, char *string2)
596 int slen1 = strlen(string1);
597 int slen2 = strlen(string2);
598 char *tmpstr1, *tmpstr2;
600 if (!string1 || !string2)
603 /* See if they are same already */
604 if (!strncmp(string1, string2, strlen(string2)))
608 if (!strchr(string1, '*'))
611 /* Take copies of the original strings as we will change them */
612 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
613 memcpy(tmpstr1, string1, slen1);
614 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
615 memcpy(tmpstr2, string2, slen2);
617 for (i = 0; i < slen1; i++) {
619 /* * wildcard. Only one * wildcard is possible. */
620 if (tmpstr1[i] == '*')
621 if (!strncmp(tmpstr1, tmpstr2, i)) {
622 memset(tmpstr2, 0, slen2);
623 strncpy(tmpstr2, tmpstr1, i);
628 if (tmpstr1[i] == '?') {
629 if (!strncmp(tmpstr1, tmpstr2, i)) {
630 if (!(slen1 < i + 1))
631 if (tmpstr1[i + 1] != '?' &&
632 tmpstr1[i + 1] != tmpstr2[i + 1])
635 if (!(slen1 < slen2))
641 /* if using *, remove it */
642 if (strchr(tmpstr1, '*'))
643 *strchr(tmpstr1, '*') = 0;
645 if (!strcmp(tmpstr1, tmpstr2)) {
646 memset(tmpstr1, 0, slen1);
647 memset(tmpstr2, 0, slen2);
653 memset(tmpstr1, 0, slen1);
654 memset(tmpstr2, 0, slen2);
660 /* Basic has function to hash strings. May be used with the SilcHashTable.
661 Note that this lowers the characters of the string (with tolower()) so
662 this is used usually with nicknames, channel and server names to provide
663 case insensitive keys. */
665 uint32 silc_hash_string(void *key, void *user_context)
667 char *s = (char *)key;
671 h = (h << 4) + tolower(*s);
672 if ((g = h & 0xf0000000)) {
682 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
684 uint32 silc_hash_uint(void *key, void *user_context)
686 return *(uint32 *)key;
689 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
691 uint32 silc_hash_ptr(void *key, void *user_context)
696 /* Hash a ID. The `user_context' is the ID type. */
698 uint32 silc_hash_id(void *key, void *user_context)
700 SilcIdType id_type = (SilcIdType)(uint32)user_context;
707 SilcClientID *id = (SilcClientID *)key;
710 /* The client ID is hashed by hashing the hash of the ID
711 (which is a truncated MD5 hash of the nickname) so that we
712 can access the entry from the cache with both Client ID but
713 with just a hash from the ID as well. */
715 for (i = 0; i < sizeof(id->hash); i++) {
716 h = (h << 4) + id->hash[i];
717 if ((g = h & 0xf0000000)) {
728 SilcServerID *id = (SilcServerID *)key;
730 h = id->port * id->rnd;
731 for (i = 0; i < id->ip.data_len; i++)
737 case SILC_ID_CHANNEL:
739 SilcChannelID *id = (SilcChannelID *)key;
741 h = id->port * id->rnd;
742 for (i = 0; i < id->ip.data_len; i++)
755 /* Hash binary data. The `user_context' is the data length. */
757 uint32 silc_hash_data(void *key, void *user_context)
759 uint32 len = (uint32)user_context, h = 0;
760 unsigned char *data = (unsigned char *)key;
763 h = (data[0] * data[len - 1] + 1) * len;
764 for (i = 0; i < len; i++)
770 /* Compares two strings. May be used as SilcHashTable comparison function. */
772 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
774 return !strcasecmp((char *)key1, (char *)key2);
777 /* Compares two ID's. May be used as SilcHashTable comparison function.
778 The Client ID's compares only the hash of the Client ID not any other
779 part of the Client ID. Other ID's are fully compared. */
781 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
783 SilcIdType id_type = (SilcIdType)(uint32)user_context;
784 return (id_type == SILC_ID_CLIENT ?
785 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
786 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
789 /* Compare two Client ID's entirely and not just the hash from the ID. */
791 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
793 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
796 /* Compares binary data. May be used as SilcHashTable comparison function. */
798 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
800 uint32 len = (uint32)user_context;
801 return !memcmp(key1, key2, len);
804 /* Parses mode mask and returns the mode as string. */
806 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
813 memset(string, 0, sizeof(string));
815 if (mode & SILC_CHANNEL_MODE_PRIVATE)
816 strncat(string, "p", 1);
818 if (mode & SILC_CHANNEL_MODE_SECRET)
819 strncat(string, "s", 1);
821 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
822 strncat(string, "k", 1);
824 if (mode & SILC_CHANNEL_MODE_INVITE)
825 strncat(string, "i", 1);
827 if (mode & SILC_CHANNEL_MODE_TOPIC)
828 strncat(string, "t", 1);
830 if (mode & SILC_CHANNEL_MODE_ULIMIT)
831 strncat(string, "l", 1);
833 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
834 strncat(string, "a", 1);
836 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
837 strncat(string, "f", 1);
839 if (mode & SILC_CHANNEL_MODE_CIPHER)
840 strncat(string, cipher, strlen(cipher));
842 if (mode & SILC_CHANNEL_MODE_HMAC)
843 strncat(string, hmac, strlen(hmac));
845 /* Rest of mode is ignored */
847 return strdup(string);
850 /* Parses channel user mode mask and returns te mode as string */
852 char *silc_client_chumode(uint32 mode)
859 memset(string, 0, sizeof(string));
861 if (mode & SILC_CHANNEL_UMODE_CHANFO)
862 strncat(string, "f", 1);
864 if (mode & SILC_CHANNEL_UMODE_CHANOP)
865 strncat(string, "o", 1);
867 return strdup(string);
870 /* Parses channel user mode and returns it as special mode character. */
872 char *silc_client_chumode_char(uint32 mode)
879 memset(string, 0, sizeof(string));
881 if (mode & SILC_CHANNEL_UMODE_CHANFO)
882 strncat(string, "*", 1);
884 if (mode & SILC_CHANNEL_UMODE_CHANOP)
885 strncat(string, "@", 1);
887 return strdup(string);