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 /* Reads a file to a buffer. The allocated buffer is returned. Length of
29 the file read is returned to the return_len argument. */
31 char *silc_file_read(const char *filename, uint32 *return_len)
37 fd = open(filename, O_RDONLY);
41 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
45 filelen = lseek(fd, (off_t)0L, SEEK_END);
50 if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
56 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
61 buffer = silc_calloc(filelen + 1, sizeof(char));
63 if ((read(fd, buffer, filelen)) == -1) {
64 memset(buffer, 0, sizeof(buffer));
66 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
72 buffer[filelen] = EOF;
75 *return_len = filelen;
80 /* Writes a buffer to the file. */
82 int silc_file_write(const char *filename, const char *buffer, uint32 len)
86 if ((fd = creat(filename, 0644)) == -1) {
87 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
92 if ((write(fd, buffer, len)) == -1) {
93 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
103 /* Writes a buffer to the file. If the file is created specific mode is
106 int silc_file_write_mode(const char *filename, const char *buffer,
107 uint32 len, int mode)
111 if ((fd = creat(filename, mode)) == -1) {
112 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
117 if ((write(fd, buffer, len)) == -1) {
118 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
128 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
129 This doesn't remove the newline sign from the destination buffer. The
130 argument begin is returned and should be passed again for the function. */
132 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
134 static int start = 0;
137 memset(dest, 0, destlen);
143 for ( ; start <= srclen; i++, start++) {
147 dest[i] = src[start];
160 /* Checks line for illegal characters. Return -1 when illegal character
161 were found. This is used to check for bad lines when reading data from
162 for example a configuration file. */
164 int silc_check_line(char *buf)
166 /* Illegal characters in line */
167 if (strchr(buf, '#')) return -1;
168 if (strchr(buf, '\'')) return -1;
169 if (strchr(buf, '\\')) return -1;
170 if (strchr(buf, '\r')) return -1;
171 if (strchr(buf, '\a')) return -1;
172 if (strchr(buf, '\b')) return -1;
173 if (strchr(buf, '\f')) return -1;
182 /* Returns current time as string. */
184 char *silc_get_time()
189 curtime = time(NULL);
190 return_time = ctime(&curtime);
191 return_time[strlen(return_time) - 1] = '\0';
196 /* Converts string to capital characters */
198 char *silc_to_upper(char *string)
201 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
203 for (i = 0; i < strlen(string); i++)
204 ret[i] = toupper(string[i]);
209 static unsigned char pem_enc[64] =
210 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
212 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
213 data string. Note: This is originally public domain code and is
216 char *silc_encode_pem(unsigned char *data, uint32 len)
219 uint32 bits, c, char_count;
226 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
228 for (i = 0; i < len; i++) {
233 if (char_count == 3) {
234 pem[j++] = pem_enc[bits >> 18];
235 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
236 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
237 pem[j++] = pem_enc[bits & 0x3f];
245 if (char_count != 0) {
246 bits <<= 16 - (8 * char_count);
247 pem[j++] = pem_enc[bits >> 18];
248 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
250 if (char_count == 1) {
254 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
262 /* Same as above but puts newline ('\n') every 72 characters. */
264 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
270 pem = silc_encode_pem(data, data_len);
273 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
275 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
290 /* Decodes PEM into data. Returns the decoded data. Note: This is
291 originally public domain code and is still PD. */
293 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
297 uint32 len, c, char_count, bits;
299 static char ialpha[256], decoder[256];
301 for (i = 64 - 1; i >= 0; i--) {
302 ialpha[pem_enc[i]] = 1;
303 decoder[pem_enc[i]] = i;
315 data = silc_calloc(((len * 6) / 8), sizeof(*data));
317 for (i = 0; i < len; i++) {
323 if (c > 127 || !ialpha[c])
329 if (char_count == 4) {
330 data[j++] = bits >> 16;
331 data[j++] = (bits >> 8) & 0xff;
332 data[j++] = bits & 0xff;
346 data[j++] = bits >> 10;
349 data[j++] = bits >> 16;
350 data[j++] = (bits >> 8) & 0xff;
360 /* Parse userfqdn string which is in user@fqdn format */
362 bool silc_parse_userfqdn(const char *string, char **left, char **right)
369 if (strchr(string, '@')) {
370 tlen = strcspn(string, "@");
373 *left = silc_calloc(tlen + 1, sizeof(char));
374 memcpy(*left, string, tlen);
378 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
379 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
383 *left = strdup(string);
389 /* Parses command line. At most `max_args' is taken. Rest of the line
390 will be allocated as the last argument if there are more than `max_args'
391 arguments in the line. Note that the command name is counted as one
392 argument and is saved. */
394 void silc_parse_command_line(unsigned char *buffer,
395 unsigned char ***parsed,
396 uint32 **parsed_lens,
397 uint32 **parsed_types,
403 const char *cp = buffer;
406 *parsed = silc_calloc(1, sizeof(**parsed));
407 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
409 /* Get the command first */
410 len = strcspn(cp, " ");
411 tmp = silc_to_upper((char *)cp);
412 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
413 memcpy((*parsed)[0], tmp, len);
415 (*parsed_lens)[0] = len;
421 /* Parse arguments */
422 if (strchr(cp, ' ') || strlen(cp) != 0) {
423 for (i = 1; i < max_args; i++) {
425 if (i != max_args - 1)
426 len = strcspn(cp, " ");
429 while (len && cp[len - 1] == ' ')
434 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
435 *parsed_lens = silc_realloc(*parsed_lens,
436 sizeof(**parsed_lens) * (argc + 1));
437 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
438 memcpy((*parsed)[argc], cp, len);
439 (*parsed_lens)[argc] = len;
451 /* Save argument types. Protocol defines all argument types but
452 this implementation makes sure that they are always in correct
453 order hence this simple code. */
454 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
455 for (i = 0; i < argc; i++)
456 (*parsed_types)[i] = i;
461 /* Formats arguments to a string and returns it after allocating memory
462 for it. It must be remembered to free it later. */
464 char *silc_format(char *fmt, ...)
467 static char buf[8192];
469 memset(buf, 0, sizeof(buf));
471 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
477 /* Renders ID to suitable to print for example to log file. */
479 static char rid[256];
481 char *silc_id_render(void *id, uint16 type)
484 unsigned char tmps[2];
486 memset(rid, 0, sizeof(rid));
490 SilcServerID *server_id = (SilcServerID *)id;
493 if (server_id->ip.data_len > 4) {
496 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
497 strcat(rid, inet_ntoa(ipv4));
500 memset(tmp, 0, sizeof(tmp));
501 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
503 SILC_PUT16_MSB(server_id->rnd, tmps);
504 memset(tmp, 0, sizeof(tmp));
505 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
511 SilcClientID *client_id = (SilcClientID *)id;
514 if (client_id->ip.data_len > 4) {
517 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
518 strcat(rid, inet_ntoa(ipv4));
521 memset(tmp, 0, sizeof(tmp));
522 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
524 memset(tmp, 0, sizeof(tmp));
525 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
526 client_id->hash[0], client_id->hash[1],
527 client_id->hash[2], client_id->hash[3]);
531 case SILC_ID_CHANNEL:
533 SilcChannelID *channel_id = (SilcChannelID *)id;
536 if (channel_id->ip.data_len > 4) {
539 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
540 strcat(rid, inet_ntoa(ipv4));
543 memset(tmp, 0, sizeof(tmp));
544 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
546 SILC_PUT16_MSB(channel_id->rnd, tmps);
547 memset(tmp, 0, sizeof(tmp));
548 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
557 /* Compares two strings. Strings may include wildcards * and ?.
558 Returns TRUE if strings match. */
560 int silc_string_compare(char *string1, char *string2)
563 int slen1 = strlen(string1);
564 int slen2 = strlen(string2);
565 char *tmpstr1, *tmpstr2;
567 if (!string1 || !string2)
570 /* See if they are same already */
571 if (!strncmp(string1, string2, strlen(string2)))
575 if (!strchr(string1, '*'))
578 /* Take copies of the original strings as we will change them */
579 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
580 memcpy(tmpstr1, string1, slen1);
581 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
582 memcpy(tmpstr2, string2, slen2);
584 for (i = 0; i < slen1; i++) {
586 /* * wildcard. Only one * wildcard is possible. */
587 if (tmpstr1[i] == '*')
588 if (!strncmp(tmpstr1, tmpstr2, i)) {
589 memset(tmpstr2, 0, slen2);
590 strncpy(tmpstr2, tmpstr1, i);
595 if (tmpstr1[i] == '?') {
596 if (!strncmp(tmpstr1, tmpstr2, i)) {
597 if (!(slen1 < i + 1))
598 if (tmpstr1[i + 1] != '?' &&
599 tmpstr1[i + 1] != tmpstr2[i + 1])
602 if (!(slen1 < slen2))
608 /* if using *, remove it */
609 if (strchr(tmpstr1, '*'))
610 *strchr(tmpstr1, '*') = 0;
612 if (!strcmp(tmpstr1, tmpstr2)) {
613 memset(tmpstr1, 0, slen1);
614 memset(tmpstr2, 0, slen2);
620 memset(tmpstr1, 0, slen1);
621 memset(tmpstr2, 0, slen2);
627 /* Basic has function to hash strings. May be used with the SilcHashTable.
628 Note that this lowers the characters of the string (with tolower()) so
629 this is used usually with nicknames, channel and server names to provide
630 case insensitive keys. */
632 uint32 silc_hash_string(void *key, void *user_context)
634 char *s = (char *)key;
638 h = (h << 4) + tolower(*s);
639 if ((g = h & 0xf0000000)) {
649 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
651 uint32 silc_hash_uint(void *key, void *user_context)
653 return *(uint32 *)key;
656 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
658 uint32 silc_hash_ptr(void *key, void *user_context)
663 /* Hash a ID. The `user_context' is the ID type. */
665 uint32 silc_hash_id(void *key, void *user_context)
667 SilcIdType id_type = (SilcIdType)(uint32)user_context;
674 SilcClientID *id = (SilcClientID *)key;
677 /* The client ID is hashed by hashing the hash of the ID
678 (which is a truncated MD5 hash of the nickname) so that we
679 can access the entry from the cache with both Client ID but
680 with just a hash from the ID as well. */
682 for (i = 0; i < sizeof(id->hash); i++) {
683 h = (h << 4) + id->hash[i];
684 if ((g = h & 0xf0000000)) {
695 SilcServerID *id = (SilcServerID *)key;
697 h = id->port * id->rnd;
698 for (i = 0; i < id->ip.data_len; i++)
704 case SILC_ID_CHANNEL:
706 SilcChannelID *id = (SilcChannelID *)key;
708 h = id->port * id->rnd;
709 for (i = 0; i < id->ip.data_len; i++)
722 /* Hash binary data. The `user_context' is the data length. */
724 uint32 silc_hash_data(void *key, void *user_context)
726 uint32 len = (uint32)user_context, h = 0;
727 unsigned char *data = (unsigned char *)key;
730 h = (data[0] * data[len - 1] + 1) * len;
731 for (i = 0; i < len; i++)
737 /* Compares two strings. May be used as SilcHashTable comparison function. */
739 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
741 return !strcasecmp((char *)key1, (char *)key2);
744 /* Compares two ID's. May be used as SilcHashTable comparison function.
745 The Client ID's compares only the hash of the Client ID not any other
746 part of the Client ID. Other ID's are fully compared. */
748 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
750 SilcIdType id_type = (SilcIdType)(uint32)user_context;
751 return (id_type == SILC_ID_CLIENT ?
752 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
753 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
756 /* Compare two Client ID's entirely and not just the hash from the ID. */
758 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
760 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
763 /* Compares binary data. May be used as SilcHashTable comparison function. */
765 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
767 uint32 len = (uint32)user_context;
768 return !memcmp(key1, key2, len);
771 /* Parses mode mask and returns the mode as string. */
773 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
780 memset(string, 0, sizeof(string));
782 if (mode & SILC_CHANNEL_MODE_PRIVATE)
783 strncat(string, "p", 1);
785 if (mode & SILC_CHANNEL_MODE_SECRET)
786 strncat(string, "s", 1);
788 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
789 strncat(string, "k", 1);
791 if (mode & SILC_CHANNEL_MODE_INVITE)
792 strncat(string, "i", 1);
794 if (mode & SILC_CHANNEL_MODE_TOPIC)
795 strncat(string, "t", 1);
797 if (mode & SILC_CHANNEL_MODE_ULIMIT)
798 strncat(string, "l", 1);
800 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
801 strncat(string, "a", 1);
803 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
804 strncat(string, "f", 1);
806 if (mode & SILC_CHANNEL_MODE_CIPHER)
807 strncat(string, cipher, strlen(cipher));
809 if (mode & SILC_CHANNEL_MODE_HMAC)
810 strncat(string, hmac, strlen(hmac));
812 /* Rest of mode is ignored */
814 return strdup(string);
817 /* Parses channel user mode mask and returns te mode as string */
819 char *silc_client_chumode(uint32 mode)
826 memset(string, 0, sizeof(string));
828 if (mode & SILC_CHANNEL_UMODE_CHANFO)
829 strncat(string, "f", 1);
831 if (mode & SILC_CHANNEL_UMODE_CHANOP)
832 strncat(string, "o", 1);
834 return strdup(string);
837 /* Parses channel user mode and returns it as special mode character. */
839 char *silc_client_chumode_char(uint32 mode)
846 memset(string, 0, sizeof(string));
848 if (mode & SILC_CHANNEL_UMODE_CHANFO)
849 strncat(string, "*", 1);
851 if (mode & SILC_CHANNEL_UMODE_CHANOP)
852 strncat(string, "@", 1);
854 return strdup(string);