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);
39 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
43 filelen = lseek(fd, (off_t)0L, SEEK_END);
48 if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
54 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
59 buffer = silc_calloc(filelen + 1, sizeof(char));
61 if ((read(fd, buffer, filelen)) == -1) {
62 memset(buffer, 0, sizeof(buffer));
64 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
70 buffer[filelen] = EOF;
73 *return_len = filelen;
78 /* Writes a buffer to the file. */
80 int silc_file_write(const char *filename, const char *buffer, uint32 len)
84 if ((fd = creat(filename, 0644)) == -1) {
85 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
90 if ((write(fd, buffer, len)) == -1) {
91 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
101 /* Writes a buffer to the file. If the file is created specific mode is
104 int silc_file_write_mode(const char *filename, const char *buffer,
105 uint32 len, int mode)
109 if ((fd = creat(filename, mode)) == -1) {
110 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
115 if ((write(fd, buffer, len)) == -1) {
116 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
126 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
127 This doesn't remove the newline sign from the destination buffer. The
128 argument begin is returned and should be passed again for the function. */
130 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
132 static int start = 0;
135 memset(dest, 0, destlen);
141 for ( ; start <= srclen; i++, start++) {
145 dest[i] = src[start];
158 /* Checks line for illegal characters. Return -1 when illegal character
159 were found. This is used to check for bad lines when reading data from
160 for example a configuration file. */
162 int silc_check_line(char *buf)
164 /* Illegal characters in line */
165 if (strchr(buf, '#')) return -1;
166 if (strchr(buf, '\'')) return -1;
167 if (strchr(buf, '\\')) return -1;
168 if (strchr(buf, '\r')) return -1;
169 if (strchr(buf, '\a')) return -1;
170 if (strchr(buf, '\b')) return -1;
171 if (strchr(buf, '\f')) return -1;
180 /* Returns current time as string. */
182 char *silc_get_time()
187 curtime = time(NULL);
188 return_time = ctime(&curtime);
189 return_time[strlen(return_time) - 1] = '\0';
194 /* Converts string to capital characters */
196 char *silc_to_upper(char *string)
199 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
201 for (i = 0; i < strlen(string); i++)
202 ret[i] = toupper(string[i]);
207 static unsigned char pem_enc[64] =
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
210 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
211 data string. Note: This is originally public domain code and is
214 char *silc_encode_pem(unsigned char *data, uint32 len)
217 uint32 bits, c, char_count;
224 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
226 for (i = 0; i < len; i++) {
231 if (char_count == 3) {
232 pem[j++] = pem_enc[bits >> 18];
233 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
234 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
235 pem[j++] = pem_enc[bits & 0x3f];
243 if (char_count != 0) {
244 bits <<= 16 - (8 * char_count);
245 pem[j++] = pem_enc[bits >> 18];
246 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
248 if (char_count == 1) {
252 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
260 /* Same as above but puts newline ('\n') every 72 characters. */
262 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
268 pem = silc_encode_pem(data, data_len);
271 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
273 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
288 /* Decodes PEM into data. Returns the decoded data. Note: This is
289 originally public domain code and is still PD. */
291 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
295 uint32 len, c, char_count, bits;
297 static char ialpha[256], decoder[256];
299 for (i = 64 - 1; i >= 0; i--) {
300 ialpha[pem_enc[i]] = 1;
301 decoder[pem_enc[i]] = i;
313 data = silc_calloc(((len * 6) / 8), sizeof(*data));
315 for (i = 0; i < len; i++) {
321 if (c > 127 || !ialpha[c])
327 if (char_count == 4) {
328 data[j++] = bits >> 16;
329 data[j++] = (bits >> 8) & 0xff;
330 data[j++] = bits & 0xff;
344 data[j++] = bits >> 10;
347 data[j++] = bits >> 16;
348 data[j++] = (bits >> 8) & 0xff;
358 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
359 support multiple same nicknames. The <num> is the final unifier if same
360 nickname is on same server. Note, this is only local format and server
361 does not know anything about these. */
363 int silc_parse_nickname(char *string, char **nickname, char **server,
371 if (strchr(string, '!')) {
373 tlen = strcspn(string, "!");
374 tmp = silc_calloc(tlen + 1, sizeof(*tmp));
375 memcpy(tmp, string, tlen);
382 if (tlen >= strlen(string))
388 if (strchr(string, '@')) {
389 tlen = strcspn(string, "@");
392 *nickname = silc_calloc(tlen + 1, sizeof(char));
393 memcpy(*nickname, string, tlen);
397 *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
398 memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
402 *nickname = strdup(string);
408 /* Parses command line. At most `max_args' is taken. Rest of the line
409 will be allocated as the last argument if there are more than `max_args'
410 arguments in the line. Note that the command name is counted as one
411 argument and is saved. */
413 void silc_parse_command_line(unsigned char *buffer,
414 unsigned char ***parsed,
415 uint32 **parsed_lens,
416 uint32 **parsed_types,
422 const char *cp = buffer;
425 *parsed = silc_calloc(1, sizeof(**parsed));
426 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
428 /* Get the command first */
429 len = strcspn(cp, " ");
430 tmp = silc_to_upper((char *)cp);
431 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
432 memcpy((*parsed)[0], tmp, len);
434 (*parsed_lens)[0] = len;
440 /* Parse arguments */
441 if (strchr(cp, ' ') || strlen(cp) != 0) {
442 for (i = 1; i < max_args; i++) {
444 if (i != max_args - 1)
445 len = strcspn(cp, " ");
448 while (len && cp[len - 1] == ' ')
453 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
454 *parsed_lens = silc_realloc(*parsed_lens,
455 sizeof(**parsed_lens) * (argc + 1));
456 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
457 memcpy((*parsed)[argc], cp, len);
458 (*parsed_lens)[argc] = len;
470 /* Save argument types. Protocol defines all argument types but
471 this implementation makes sure that they are always in correct
472 order hence this simple code. */
473 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
474 for (i = 0; i < argc; i++)
475 (*parsed_types)[i] = i;
480 /* Formats arguments to a string and returns it after allocating memory
481 for it. It must be remembered to free it later. */
483 char *silc_format(char *fmt, ...)
486 static char buf[8192];
488 memset(buf, 0, sizeof(buf));
490 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
496 /* Renders ID to suitable to print for example to log file. */
498 static char rid[256];
500 char *silc_id_render(void *id, uint16 type)
503 unsigned char tmps[2];
505 memset(rid, 0, sizeof(rid));
509 SilcServerID *server_id = (SilcServerID *)id;
512 if (server_id->ip.data_len > 4) {
515 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
516 strcat(rid, inet_ntoa(ipv4));
519 memset(tmp, 0, sizeof(tmp));
520 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
522 SILC_PUT16_MSB(server_id->rnd, tmps);
523 memset(tmp, 0, sizeof(tmp));
524 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
530 SilcClientID *client_id = (SilcClientID *)id;
533 if (client_id->ip.data_len > 4) {
536 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
537 strcat(rid, inet_ntoa(ipv4));
540 memset(tmp, 0, sizeof(tmp));
541 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
543 memset(tmp, 0, sizeof(tmp));
544 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
545 client_id->hash[0], client_id->hash[1],
546 client_id->hash[2], client_id->hash[3]);
550 case SILC_ID_CHANNEL:
552 SilcChannelID *channel_id = (SilcChannelID *)id;
555 if (channel_id->ip.data_len > 4) {
558 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
559 strcat(rid, inet_ntoa(ipv4));
562 memset(tmp, 0, sizeof(tmp));
563 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
565 SILC_PUT16_MSB(channel_id->rnd, tmps);
566 memset(tmp, 0, sizeof(tmp));
567 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
576 /* Compares two strings. Strings may include wildcards * and ?.
577 Returns TRUE if strings match. */
579 int silc_string_compare(char *string1, char *string2)
582 int slen1 = strlen(string1);
583 int slen2 = strlen(string2);
584 char *tmpstr1, *tmpstr2;
586 if (!string1 || !string2)
589 /* See if they are same already */
590 if (!strncmp(string1, string2, strlen(string2)))
594 if (!strchr(string1, '*'))
597 /* Take copies of the original strings as we will change them */
598 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
599 memcpy(tmpstr1, string1, slen1);
600 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
601 memcpy(tmpstr2, string2, slen2);
603 for (i = 0; i < slen1; i++) {
605 /* * wildcard. Only one * wildcard is possible. */
606 if (tmpstr1[i] == '*')
607 if (!strncmp(tmpstr1, tmpstr2, i)) {
608 memset(tmpstr2, 0, slen2);
609 strncpy(tmpstr2, tmpstr1, i);
614 if (tmpstr1[i] == '?') {
615 if (!strncmp(tmpstr1, tmpstr2, i)) {
616 if (!(slen1 < i + 1))
617 if (tmpstr1[i + 1] != '?' &&
618 tmpstr1[i + 1] != tmpstr2[i + 1])
621 if (!(slen1 < slen2))
627 /* if using *, remove it */
628 if (strchr(tmpstr1, '*'))
629 *strchr(tmpstr1, '*') = 0;
631 if (!strcmp(tmpstr1, tmpstr2)) {
632 memset(tmpstr1, 0, slen1);
633 memset(tmpstr2, 0, slen2);
639 memset(tmpstr1, 0, slen1);
640 memset(tmpstr2, 0, slen2);
646 /* Basic has function to hash strings. May be used with the SilcHashTable.
647 Note that this lowers the characters of the string (with tolower()) so
648 this is used usually with nicknames, channel and server names to provide
649 case insensitive keys. */
651 uint32 silc_hash_string(void *key, void *user_context)
653 char *s = (char *)key;
657 h = (h << 4) + tolower(*s);
658 if ((g = h & 0xf0000000)) {
668 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
670 uint32 silc_hash_uint(void *key, void *user_context)
672 return *(uint32 *)key;
675 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
677 uint32 silc_hash_ptr(void *key, void *user_context)
682 /* Hash a ID. The `user_context' is the ID type. */
684 uint32 silc_hash_id(void *key, void *user_context)
686 SilcIdType id_type = (SilcIdType)(uint32)user_context;
693 SilcClientID *id = (SilcClientID *)key;
696 /* The client ID is hashed by hashing the hash of the ID
697 (which is a truncated MD5 hash of the nickname) so that we
698 can access the entry from the cache with both Client ID but
699 with just a hash from the ID as well. */
701 for (i = 0; i < sizeof(id->hash); i++) {
702 h = (h << 4) + id->hash[i];
703 if ((g = h & 0xf0000000)) {
714 SilcServerID *id = (SilcServerID *)key;
716 h = id->port * id->rnd;
717 for (i = 0; i < id->ip.data_len; i++)
723 case SILC_ID_CHANNEL:
725 SilcChannelID *id = (SilcChannelID *)key;
727 h = id->port * id->rnd;
728 for (i = 0; i < id->ip.data_len; i++)
741 /* Hash binary data. The `user_context' is the data length. */
743 uint32 silc_hash_data(void *key, void *user_context)
745 uint32 len = (uint32)user_context, h = 0;
746 unsigned char *data = (unsigned char *)key;
749 h = (data[0] * data[len - 1] + 1) * len;
750 for (i = 0; i < len; i++)
756 /* Compares two strings. May be used as SilcHashTable comparison function. */
758 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
760 return !strcasecmp((char *)key1, (char *)key2);
763 /* Compares two ID's. May be used as SilcHashTable comparison function.
764 The Client ID's compares only the hash of the Client ID not any other
765 part of the Client ID. Other ID's are fully compared. */
767 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
769 SilcIdType id_type = (SilcIdType)(uint32)user_context;
770 return (id_type == SILC_ID_CLIENT ?
771 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
772 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
775 /* Compare two Client ID's entirely and not just the hash from the ID. */
777 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
779 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
782 /* Compares binary data. May be used as SilcHashTable comparison function. */
784 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
786 uint32 len = (uint32)user_context;
787 return !memcmp(key1, key2, len);
790 /* Parses mode mask and returns the mode as string. */
792 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
799 memset(string, 0, sizeof(string));
801 if (mode & SILC_CHANNEL_MODE_PRIVATE)
802 strncat(string, "p", 1);
804 if (mode & SILC_CHANNEL_MODE_SECRET)
805 strncat(string, "s", 1);
807 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
808 strncat(string, "k", 1);
810 if (mode & SILC_CHANNEL_MODE_INVITE)
811 strncat(string, "i", 1);
813 if (mode & SILC_CHANNEL_MODE_TOPIC)
814 strncat(string, "t", 1);
816 if (mode & SILC_CHANNEL_MODE_ULIMIT)
817 strncat(string, "l", 1);
819 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
820 strncat(string, "a", 1);
822 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
823 strncat(string, "f", 1);
825 if (mode & SILC_CHANNEL_MODE_CIPHER)
826 strncat(string, cipher, strlen(cipher));
828 if (mode & SILC_CHANNEL_MODE_HMAC)
829 strncat(string, hmac, strlen(hmac));
831 /* Rest of mode is ignored */
833 return strdup(string);
836 /* Parses channel user mode mask and returns te mode as string */
838 char *silc_client_chumode(uint32 mode)
845 memset(string, 0, sizeof(string));
847 if (mode & SILC_CHANNEL_UMODE_CHANFO)
848 strncat(string, "f", 1);
850 if (mode & SILC_CHANNEL_UMODE_CHANOP)
851 strncat(string, "o", 1);
853 return strdup(string);
856 /* Parses channel user mode and returns it as special mode character. */
858 char *silc_client_chumode_char(uint32 mode)
865 memset(string, 0, sizeof(string));
867 if (mode & SILC_CHANNEL_UMODE_CHANFO)
868 strncat(string, "*", 1);
870 if (mode & SILC_CHANNEL_UMODE_CHANOP)
871 strncat(string, "@", 1);
873 return strdup(string);