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 userfqdn string which is in user@fqdn format */
360 bool silc_parse_userfqdn(const char *string, char **left, char **right)
367 if (strchr(string, '@')) {
368 tlen = strcspn(string, "@");
371 *left = silc_calloc(tlen + 1, sizeof(char));
372 memcpy(*left, string, tlen);
376 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
377 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
381 *left = strdup(string);
387 /* Parses command line. At most `max_args' is taken. Rest of the line
388 will be allocated as the last argument if there are more than `max_args'
389 arguments in the line. Note that the command name is counted as one
390 argument and is saved. */
392 void silc_parse_command_line(unsigned char *buffer,
393 unsigned char ***parsed,
394 uint32 **parsed_lens,
395 uint32 **parsed_types,
401 const char *cp = buffer;
404 *parsed = silc_calloc(1, sizeof(**parsed));
405 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
407 /* Get the command first */
408 len = strcspn(cp, " ");
409 tmp = silc_to_upper((char *)cp);
410 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
411 memcpy((*parsed)[0], tmp, len);
413 (*parsed_lens)[0] = len;
419 /* Parse arguments */
420 if (strchr(cp, ' ') || strlen(cp) != 0) {
421 for (i = 1; i < max_args; i++) {
423 if (i != max_args - 1)
424 len = strcspn(cp, " ");
427 while (len && cp[len - 1] == ' ')
432 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
433 *parsed_lens = silc_realloc(*parsed_lens,
434 sizeof(**parsed_lens) * (argc + 1));
435 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
436 memcpy((*parsed)[argc], cp, len);
437 (*parsed_lens)[argc] = len;
449 /* Save argument types. Protocol defines all argument types but
450 this implementation makes sure that they are always in correct
451 order hence this simple code. */
452 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
453 for (i = 0; i < argc; i++)
454 (*parsed_types)[i] = i;
459 /* Formats arguments to a string and returns it after allocating memory
460 for it. It must be remembered to free it later. */
462 char *silc_format(char *fmt, ...)
465 static char buf[8192];
467 memset(buf, 0, sizeof(buf));
469 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
475 /* Renders ID to suitable to print for example to log file. */
477 static char rid[256];
479 char *silc_id_render(void *id, uint16 type)
482 unsigned char tmps[2];
484 memset(rid, 0, sizeof(rid));
488 SilcServerID *server_id = (SilcServerID *)id;
491 if (server_id->ip.data_len > 4) {
494 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
495 strcat(rid, inet_ntoa(ipv4));
498 memset(tmp, 0, sizeof(tmp));
499 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
501 SILC_PUT16_MSB(server_id->rnd, tmps);
502 memset(tmp, 0, sizeof(tmp));
503 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
509 SilcClientID *client_id = (SilcClientID *)id;
512 if (client_id->ip.data_len > 4) {
515 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
516 strcat(rid, inet_ntoa(ipv4));
519 memset(tmp, 0, sizeof(tmp));
520 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
522 memset(tmp, 0, sizeof(tmp));
523 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
524 client_id->hash[0], client_id->hash[1],
525 client_id->hash[2], client_id->hash[3]);
529 case SILC_ID_CHANNEL:
531 SilcChannelID *channel_id = (SilcChannelID *)id;
534 if (channel_id->ip.data_len > 4) {
537 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
538 strcat(rid, inet_ntoa(ipv4));
541 memset(tmp, 0, sizeof(tmp));
542 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
544 SILC_PUT16_MSB(channel_id->rnd, tmps);
545 memset(tmp, 0, sizeof(tmp));
546 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
555 /* Compares two strings. Strings may include wildcards * and ?.
556 Returns TRUE if strings match. */
558 int silc_string_compare(char *string1, char *string2)
561 int slen1 = strlen(string1);
562 int slen2 = strlen(string2);
563 char *tmpstr1, *tmpstr2;
565 if (!string1 || !string2)
568 /* See if they are same already */
569 if (!strncmp(string1, string2, strlen(string2)))
573 if (!strchr(string1, '*'))
576 /* Take copies of the original strings as we will change them */
577 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
578 memcpy(tmpstr1, string1, slen1);
579 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
580 memcpy(tmpstr2, string2, slen2);
582 for (i = 0; i < slen1; i++) {
584 /* * wildcard. Only one * wildcard is possible. */
585 if (tmpstr1[i] == '*')
586 if (!strncmp(tmpstr1, tmpstr2, i)) {
587 memset(tmpstr2, 0, slen2);
588 strncpy(tmpstr2, tmpstr1, i);
593 if (tmpstr1[i] == '?') {
594 if (!strncmp(tmpstr1, tmpstr2, i)) {
595 if (!(slen1 < i + 1))
596 if (tmpstr1[i + 1] != '?' &&
597 tmpstr1[i + 1] != tmpstr2[i + 1])
600 if (!(slen1 < slen2))
606 /* if using *, remove it */
607 if (strchr(tmpstr1, '*'))
608 *strchr(tmpstr1, '*') = 0;
610 if (!strcmp(tmpstr1, tmpstr2)) {
611 memset(tmpstr1, 0, slen1);
612 memset(tmpstr2, 0, slen2);
618 memset(tmpstr1, 0, slen1);
619 memset(tmpstr2, 0, slen2);
625 /* Basic has function to hash strings. May be used with the SilcHashTable.
626 Note that this lowers the characters of the string (with tolower()) so
627 this is used usually with nicknames, channel and server names to provide
628 case insensitive keys. */
630 uint32 silc_hash_string(void *key, void *user_context)
632 char *s = (char *)key;
636 h = (h << 4) + tolower(*s);
637 if ((g = h & 0xf0000000)) {
647 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
649 uint32 silc_hash_uint(void *key, void *user_context)
651 return *(uint32 *)key;
654 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
656 uint32 silc_hash_ptr(void *key, void *user_context)
661 /* Hash a ID. The `user_context' is the ID type. */
663 uint32 silc_hash_id(void *key, void *user_context)
665 SilcIdType id_type = (SilcIdType)(uint32)user_context;
672 SilcClientID *id = (SilcClientID *)key;
675 /* The client ID is hashed by hashing the hash of the ID
676 (which is a truncated MD5 hash of the nickname) so that we
677 can access the entry from the cache with both Client ID but
678 with just a hash from the ID as well. */
680 for (i = 0; i < sizeof(id->hash); i++) {
681 h = (h << 4) + id->hash[i];
682 if ((g = h & 0xf0000000)) {
693 SilcServerID *id = (SilcServerID *)key;
695 h = id->port * id->rnd;
696 for (i = 0; i < id->ip.data_len; i++)
702 case SILC_ID_CHANNEL:
704 SilcChannelID *id = (SilcChannelID *)key;
706 h = id->port * id->rnd;
707 for (i = 0; i < id->ip.data_len; i++)
720 /* Hash binary data. The `user_context' is the data length. */
722 uint32 silc_hash_data(void *key, void *user_context)
724 uint32 len = (uint32)user_context, h = 0;
725 unsigned char *data = (unsigned char *)key;
728 h = (data[0] * data[len - 1] + 1) * len;
729 for (i = 0; i < len; i++)
735 /* Compares two strings. May be used as SilcHashTable comparison function. */
737 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
739 return !strcasecmp((char *)key1, (char *)key2);
742 /* Compares two ID's. May be used as SilcHashTable comparison function.
743 The Client ID's compares only the hash of the Client ID not any other
744 part of the Client ID. Other ID's are fully compared. */
746 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
748 SilcIdType id_type = (SilcIdType)(uint32)user_context;
749 return (id_type == SILC_ID_CLIENT ?
750 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
751 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
754 /* Compare two Client ID's entirely and not just the hash from the ID. */
756 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
758 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
761 /* Compares binary data. May be used as SilcHashTable comparison function. */
763 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
765 uint32 len = (uint32)user_context;
766 return !memcmp(key1, key2, len);
769 /* Parses mode mask and returns the mode as string. */
771 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
778 memset(string, 0, sizeof(string));
780 if (mode & SILC_CHANNEL_MODE_PRIVATE)
781 strncat(string, "p", 1);
783 if (mode & SILC_CHANNEL_MODE_SECRET)
784 strncat(string, "s", 1);
786 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
787 strncat(string, "k", 1);
789 if (mode & SILC_CHANNEL_MODE_INVITE)
790 strncat(string, "i", 1);
792 if (mode & SILC_CHANNEL_MODE_TOPIC)
793 strncat(string, "t", 1);
795 if (mode & SILC_CHANNEL_MODE_ULIMIT)
796 strncat(string, "l", 1);
798 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
799 strncat(string, "a", 1);
801 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
802 strncat(string, "f", 1);
804 if (mode & SILC_CHANNEL_MODE_CIPHER)
805 strncat(string, cipher, strlen(cipher));
807 if (mode & SILC_CHANNEL_MODE_HMAC)
808 strncat(string, hmac, strlen(hmac));
810 /* Rest of mode is ignored */
812 return strdup(string);
815 /* Parses channel user mode mask and returns te mode as string */
817 char *silc_client_chumode(uint32 mode)
824 memset(string, 0, sizeof(string));
826 if (mode & SILC_CHANNEL_UMODE_CHANFO)
827 strncat(string, "f", 1);
829 if (mode & SILC_CHANNEL_UMODE_CHANOP)
830 strncat(string, "o", 1);
832 return strdup(string);
835 /* Parses channel user mode and returns it as special mode character. */
837 char *silc_client_chumode_char(uint32 mode)
844 memset(string, 0, sizeof(string));
846 if (mode & SILC_CHANNEL_UMODE_CHANFO)
847 strncat(string, "*", 1);
849 if (mode & SILC_CHANNEL_UMODE_CHANOP)
850 strncat(string, "@", 1);
852 return strdup(string);