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 /* Inspects the `string' for wildcards and returns regex string that can
647 be used by the GNU regex library. A comma (`,') in the `string' means
648 that the string is list. */
650 char *silc_string_regexify(const char *string)
655 len = strlen(string);
657 for (i = 0; i < len; i++)
658 if (string[i] == '*' || string[i] == '?')
661 regex = silc_calloc(len + count, sizeof(*regex));
667 for (i = 0; i < len; i++) {
668 if (string[i] == '*' || string[i] == '?') {
671 } else if (string[i] == ',') {
677 regex[count] = string[i];
681 regex[count - 1] = ')';
687 /* Combines two regex strings into one regex string so that they can be
688 used as one by the GNU regex library. The `string2' is combine into
691 char *silc_string_regex_combine(const char *string1, const char *string2)
696 len1 = strlen(string1);
697 len2 = strlen(string2);
699 tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
700 strncat(tmp, string1, len1 - 2);
701 strncat(tmp, "|", 1);
702 strncat(tmp, string2 + 1, len2 - 1);
707 /* Matches the two strings and returns TRUE if the strings match. */
709 int silc_string_regex_match(const char *regex, const char *string)
714 if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
717 if (regexec(&preg, string, 0, NULL, 0) == 0)
725 /* Do regex match to the two strings `string1' and `string2'. If the
726 `string2' matches the `string1' this returns TRUE. */
728 int silc_string_match(const char *string1, const char *string2)
733 s1 = silc_string_regexify(string1);
734 ret = silc_string_regex_match(s1, string2);
740 /* Returns the username of the user. If the global variable LOGNAME
741 does not exists we will get the name from the password file. */
743 char *silc_get_username()
745 char *logname = NULL;
747 logname = getenv("LOGNAME");
749 logname = getlogin();
753 pw = getpwuid(getuid());
755 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
759 logname = pw->pw_name;
763 return strdup(logname);
766 /* Returns the real name of ther user. */
768 char *silc_get_real_name()
770 char *realname = NULL;
773 pw = getpwuid(getuid());
775 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
779 if (strchr(pw->pw_gecos, ','))
780 *strchr(pw->pw_gecos, ',') = 0;
782 realname = strdup(pw->pw_gecos);
787 /* Basic has function to hash strings. May be used with the SilcHashTable.
788 Note that this lowers the characters of the string (with tolower()) so
789 this is used usually with nicknames, channel and server names to provide
790 case insensitive keys. */
792 uint32 silc_hash_string(void *key, void *user_context)
794 char *s = (char *)key;
798 h = (h << 4) + tolower(*s);
799 if ((g = h & 0xf0000000)) {
809 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
811 uint32 silc_hash_uint(void *key, void *user_context)
813 return *(uint32 *)key;
816 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
818 uint32 silc_hash_ptr(void *key, void *user_context)
823 /* Hash a ID. The `user_context' is the ID type. */
825 uint32 silc_hash_id(void *key, void *user_context)
827 SilcIdType id_type = (SilcIdType)(uint32)user_context;
834 SilcClientID *id = (SilcClientID *)key;
837 /* The client ID is hashed by hashing the hash of the ID
838 (which is a truncated MD5 hash of the nickname) so that we
839 can access the entry from the cache with both Client ID but
840 with just a hash from the ID as well. */
842 for (i = 0; i < sizeof(id->hash); i++) {
843 h = (h << 4) + id->hash[i];
844 if ((g = h & 0xf0000000)) {
855 SilcServerID *id = (SilcServerID *)key;
857 h = id->port * id->rnd;
858 for (i = 0; i < id->ip.data_len; i++)
864 case SILC_ID_CHANNEL:
866 SilcChannelID *id = (SilcChannelID *)key;
868 h = id->port * id->rnd;
869 for (i = 0; i < id->ip.data_len; i++)
882 /* Hash binary data. The `user_context' is the data length. */
884 uint32 silc_hash_data(void *key, void *user_context)
886 uint32 len = (uint32)user_context, h = 0;
887 unsigned char *data = (unsigned char *)key;
890 h = (data[0] * data[len - 1] + 1) * len;
891 for (i = 0; i < len; i++)
897 /* Compares two strings. May be used as SilcHashTable comparison function. */
899 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
901 return !strcasecmp((char *)key1, (char *)key2);
904 /* Compares two ID's. May be used as SilcHashTable comparison function.
905 The Client ID's compares only the hash of the Client ID not any other
906 part of the Client ID. Other ID's are fully compared. */
908 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
910 SilcIdType id_type = (SilcIdType)(uint32)user_context;
911 return (id_type == SILC_ID_CLIENT ?
912 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
913 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
916 /* Compare two Client ID's entirely and not just the hash from the ID. */
918 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
920 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
923 /* Compares binary data. May be used as SilcHashTable comparison function. */
925 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
927 uint32 len = (uint32)user_context;
928 return !memcmp(key1, key2, len);
931 /* Parses mode mask and returns the mode as string. */
933 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
940 memset(string, 0, sizeof(string));
942 if (mode & SILC_CHANNEL_MODE_PRIVATE)
943 strncat(string, "p", 1);
945 if (mode & SILC_CHANNEL_MODE_SECRET)
946 strncat(string, "s", 1);
948 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
949 strncat(string, "k", 1);
951 if (mode & SILC_CHANNEL_MODE_INVITE)
952 strncat(string, "i", 1);
954 if (mode & SILC_CHANNEL_MODE_TOPIC)
955 strncat(string, "t", 1);
957 if (mode & SILC_CHANNEL_MODE_ULIMIT)
958 strncat(string, "l", 1);
960 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
961 strncat(string, "a", 1);
963 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
964 strncat(string, "f", 1);
966 if (mode & SILC_CHANNEL_MODE_CIPHER)
967 strncat(string, cipher, strlen(cipher));
969 if (mode & SILC_CHANNEL_MODE_HMAC)
970 strncat(string, hmac, strlen(hmac));
972 /* Rest of mode is ignored */
974 return strdup(string);
977 /* Parses channel user mode mask and returns te mode as string */
979 char *silc_client_chumode(uint32 mode)
986 memset(string, 0, sizeof(string));
988 if (mode & SILC_CHANNEL_UMODE_CHANFO)
989 strncat(string, "f", 1);
991 if (mode & SILC_CHANNEL_UMODE_CHANOP)
992 strncat(string, "o", 1);
994 return strdup(string);
997 /* Parses channel user mode and returns it as special mode character. */
999 char *silc_client_chumode_char(uint32 mode)
1006 memset(string, 0, sizeof(string));
1008 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1009 strncat(string, "*", 1);
1011 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1012 strncat(string, "@", 1);
1014 return strdup(string);