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;
424 *parsed = silc_calloc(1, sizeof(**parsed));
425 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
427 /* Get the command first */
428 len = strcspn(cp, " ");
429 (*parsed)[0] = silc_to_upper((char *)cp);
430 (*parsed_lens)[0] = len;
434 /* Parse arguments */
435 if (strchr(cp, ' ') || strlen(cp) != 0) {
436 for (i = 1; i < max_args; i++) {
438 if (i != max_args - 1)
439 len = strcspn(cp, " ");
443 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
444 *parsed_lens = silc_realloc(*parsed_lens,
445 sizeof(**parsed_lens) * (argc + 1));
446 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
447 memcpy((*parsed)[argc], cp, len);
448 (*parsed_lens)[argc] = len;
459 /* Save argument types. Protocol defines all argument types but
460 this implementation makes sure that they are always in correct
461 order hence this simple code. */
462 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
463 for (i = 0; i < argc; i++)
464 (*parsed_types)[i] = i;
469 /* Formats arguments to a string and returns it after allocating memory
470 for it. It must be remembered to free it later. */
472 char *silc_format(char *fmt, ...)
475 static char buf[8192];
477 memset(buf, 0, sizeof(buf));
479 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
485 /* Renders ID to suitable to print for example to log file. */
487 static char rid[256];
489 char *silc_id_render(void *id, uint16 type)
492 unsigned char tmps[2];
494 memset(rid, 0, sizeof(rid));
498 SilcServerID *server_id = (SilcServerID *)id;
501 if (server_id->ip.data_len > 4) {
504 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
505 strcat(rid, inet_ntoa(ipv4));
508 memset(tmp, 0, sizeof(tmp));
509 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
511 SILC_PUT16_MSB(server_id->rnd, tmps);
512 memset(tmp, 0, sizeof(tmp));
513 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
519 SilcClientID *client_id = (SilcClientID *)id;
522 if (client_id->ip.data_len > 4) {
525 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
526 strcat(rid, inet_ntoa(ipv4));
529 memset(tmp, 0, sizeof(tmp));
530 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
532 memset(tmp, 0, sizeof(tmp));
533 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
534 client_id->hash[0], client_id->hash[1],
535 client_id->hash[2], client_id->hash[3]);
539 case SILC_ID_CHANNEL:
541 SilcChannelID *channel_id = (SilcChannelID *)id;
544 if (channel_id->ip.data_len > 4) {
547 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
548 strcat(rid, inet_ntoa(ipv4));
551 memset(tmp, 0, sizeof(tmp));
552 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
554 SILC_PUT16_MSB(channel_id->rnd, tmps);
555 memset(tmp, 0, sizeof(tmp));
556 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
565 /* Compares two strings. Strings may include wildcards * and ?.
566 Returns TRUE if strings match. */
568 int silc_string_compare(char *string1, char *string2)
571 int slen1 = strlen(string1);
572 int slen2 = strlen(string2);
573 char *tmpstr1, *tmpstr2;
575 if (!string1 || !string2)
578 /* See if they are same already */
579 if (!strncmp(string1, string2, strlen(string2)))
583 if (!strchr(string1, '*'))
586 /* Take copies of the original strings as we will change them */
587 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
588 memcpy(tmpstr1, string1, slen1);
589 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
590 memcpy(tmpstr2, string2, slen2);
592 for (i = 0; i < slen1; i++) {
594 /* * wildcard. Only one * wildcard is possible. */
595 if (tmpstr1[i] == '*')
596 if (!strncmp(tmpstr1, tmpstr2, i)) {
597 memset(tmpstr2, 0, slen2);
598 strncpy(tmpstr2, tmpstr1, i);
603 if (tmpstr1[i] == '?') {
604 if (!strncmp(tmpstr1, tmpstr2, i)) {
605 if (!(slen1 < i + 1))
606 if (tmpstr1[i + 1] != '?' &&
607 tmpstr1[i + 1] != tmpstr2[i + 1])
610 if (!(slen1 < slen2))
616 /* if using *, remove it */
617 if (strchr(tmpstr1, '*'))
618 *strchr(tmpstr1, '*') = 0;
620 if (!strcmp(tmpstr1, tmpstr2)) {
621 memset(tmpstr1, 0, slen1);
622 memset(tmpstr2, 0, slen2);
628 memset(tmpstr1, 0, slen1);
629 memset(tmpstr2, 0, slen2);
635 /* Inspects the `string' for wildcards and returns regex string that can
636 be used by the GNU regex library. A comma (`,') in the `string' means
637 that the string is list. */
639 char *silc_string_regexify(const char *string)
644 len = strlen(string);
646 for (i = 0; i < len; i++)
647 if (string[i] == '*' || string[i] == '?')
650 regex = silc_calloc(len + count, sizeof(*regex));
656 for (i = 0; i < len; i++) {
657 if (string[i] == '*' || string[i] == '?') {
660 } else if (string[i] == ',') {
666 regex[count] = string[i];
670 regex[count - 1] = ')';
676 /* Combines two regex strings into one regex string so that they can be
677 used as one by the GNU regex library. The `string2' is combine into
680 char *silc_string_regex_combine(const char *string1, const char *string2)
685 len1 = strlen(string1);
686 len2 = strlen(string2);
688 tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
689 strncat(tmp, string1, len1 - 2);
690 strncat(tmp, "|", 1);
691 strncat(tmp, string2 + 1, len2 - 1);
696 /* Matches the two strings and returns TRUE if the strings match. */
698 int silc_string_regex_match(const char *regex, const char *string)
703 if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
706 if (regexec(&preg, string, 0, NULL, 0) == 0)
714 /* Do regex match to the two strings `string1' and `string2'. If the
715 `string2' matches the `string1' this returns TRUE. */
717 int silc_string_match(const char *string1, const char *string2)
722 s1 = silc_string_regexify(string1);
723 ret = silc_string_regex_match(s1, string2);
729 /* Returns the username of the user. If the global variable LOGNAME
730 does not exists we will get the name from the password file. */
732 char *silc_get_username()
734 char *logname = NULL;
736 logname = getenv("LOGNAME");
738 logname = getlogin();
742 pw = getpwuid(getuid());
744 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
748 logname = pw->pw_name;
752 return strdup(logname);
755 /* Returns the real name of ther user. */
757 char *silc_get_real_name()
759 char *realname = NULL;
762 pw = getpwuid(getuid());
764 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
768 if (strchr(pw->pw_gecos, ','))
769 *strchr(pw->pw_gecos, ',') = 0;
771 realname = strdup(pw->pw_gecos);
776 /* Basic has function to hash strings. May be used with the SilcHashTable.
777 Note that this lowers the characters of the string (with tolower()) so
778 this is used usually with nicknames, channel and server names to provide
779 case insensitive keys. */
781 uint32 silc_hash_string(void *key, void *user_context)
783 char *s = (char *)key;
787 h = (h << 4) + tolower(*s);
788 if ((g = h & 0xf0000000)) {
798 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
800 uint32 silc_hash_uint(void *key, void *user_context)
802 return *(uint32 *)key;
805 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
807 uint32 silc_hash_ptr(void *key, void *user_context)
812 /* Hash a ID. The `user_context' is the ID type. */
814 uint32 silc_hash_id(void *key, void *user_context)
816 SilcIdType id_type = (SilcIdType)(uint32)user_context;
823 SilcClientID *id = (SilcClientID *)key;
826 /* The client ID is hashed by hashing the hash of the ID
827 (which is a truncated MD5 hash of the nickname) so that we
828 can access the entry from the cache with both Client ID but
829 with just a hash from the ID as well. */
831 for (i = 0; i < sizeof(id->hash); i++) {
832 h = (h << 4) + id->hash[i];
833 if ((g = h & 0xf0000000)) {
844 SilcServerID *id = (SilcServerID *)key;
846 h = id->port * id->rnd;
847 for (i = 0; i < id->ip.data_len; i++)
853 case SILC_ID_CHANNEL:
855 SilcChannelID *id = (SilcChannelID *)key;
857 h = id->port * id->rnd;
858 for (i = 0; i < id->ip.data_len; i++)
871 /* Hash binary data. The `user_context' is the data length. */
873 uint32 silc_hash_data(void *key, void *user_context)
875 uint32 len = (uint32)user_context, h = 0;
876 unsigned char *data = (unsigned char *)key;
879 h = (data[0] * data[len - 1] + 1) * len;
880 for (i = 0; i < len; i++)
886 /* Compares two strings. May be used as SilcHashTable comparison function. */
888 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
890 return !strcasecmp((char *)key1, (char *)key2);
893 /* Compares two ID's. May be used as SilcHashTable comparison function.
894 The Client ID's compares only the hash of the Client ID not any other
895 part of the Client ID. Other ID's are fully compared. */
897 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
899 SilcIdType id_type = (SilcIdType)(uint32)user_context;
900 return (id_type == SILC_ID_CLIENT ?
901 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
902 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
905 /* Compare two Client ID's entirely and not just the hash from the ID. */
907 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
909 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
912 /* Compares binary data. May be used as SilcHashTable comparison function. */
914 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
916 uint32 len = (uint32)user_context;
917 return !memcmp(key1, key2, len);
920 /* Parses mode mask and returns the mode as string. */
922 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
929 memset(string, 0, sizeof(string));
931 if (mode & SILC_CHANNEL_MODE_PRIVATE)
932 strncat(string, "p", 1);
934 if (mode & SILC_CHANNEL_MODE_SECRET)
935 strncat(string, "s", 1);
937 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
938 strncat(string, "k", 1);
940 if (mode & SILC_CHANNEL_MODE_INVITE)
941 strncat(string, "i", 1);
943 if (mode & SILC_CHANNEL_MODE_TOPIC)
944 strncat(string, "t", 1);
946 if (mode & SILC_CHANNEL_MODE_ULIMIT)
947 strncat(string, "l", 1);
949 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
950 strncat(string, "a", 1);
952 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
953 strncat(string, "f", 1);
955 if (mode & SILC_CHANNEL_MODE_CIPHER)
956 strncat(string, cipher, strlen(cipher));
958 if (mode & SILC_CHANNEL_MODE_HMAC)
959 strncat(string, hmac, strlen(hmac));
961 /* Rest of mode is ignored */
963 return strdup(string);
966 /* Parses channel user mode mask and returns te mode as string */
968 char *silc_client_chumode(uint32 mode)
975 memset(string, 0, sizeof(string));
977 if (mode & SILC_CHANNEL_UMODE_CHANFO)
978 strncat(string, "f", 1);
980 if (mode & SILC_CHANNEL_UMODE_CHANOP)
981 strncat(string, "o", 1);
983 return strdup(string);
986 /* Parses channel user mode and returns it as special mode character. */
988 char *silc_client_chumode_char(uint32 mode)
995 memset(string, 0, sizeof(string));
997 if (mode & SILC_CHANNEL_UMODE_CHANFO)
998 strncat(string, "*", 1);
1000 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1001 strncat(string, "@", 1);
1003 return strdup(string);